mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 708116. Factor out logic for updating the current frame of a video element into a helper object. r=doublec
This commit is contained in:
parent
821e0def4e
commit
8b57a3e190
@ -48,8 +48,8 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "nsAudioStream.h"
|
||||
#include "VideoFrameContainer.h"
|
||||
|
||||
// Define to output information on decoding and painting framerate
|
||||
/* #define DEBUG_FRAME_RATE 1 */
|
||||
@ -60,12 +60,10 @@ typedef PRUint16 nsMediaReadyState;
|
||||
class nsHTMLMediaElement : public nsGenericHTMLElement,
|
||||
public nsIObserver
|
||||
{
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
|
||||
public:
|
||||
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
typedef mozilla::TimeDuration TimeDuration;
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
typedef mozilla::VideoFrameContainer VideoFrameContainer;
|
||||
|
||||
enum CanPlayStatus {
|
||||
CANPLAY_NO,
|
||||
@ -192,7 +190,12 @@ public:
|
||||
|
||||
// Called by the media decoder and the video frame to get the
|
||||
// ImageContainer containing the video data.
|
||||
ImageContainer* GetImageContainer();
|
||||
VideoFrameContainer* GetVideoFrameContainer();
|
||||
ImageContainer* GetImageContainer()
|
||||
{
|
||||
VideoFrameContainer* container = GetVideoFrameContainer();
|
||||
return container ? container->GetImageContainer() : nsnull;
|
||||
}
|
||||
|
||||
// Called by the video frame to get the print surface, if this is
|
||||
// a static document and we're not actually playing video
|
||||
@ -569,9 +572,9 @@ protected:
|
||||
// The current decoder. Load() has been called on this decoder.
|
||||
nsRefPtr<nsMediaDecoder> mDecoder;
|
||||
|
||||
// A reference to the ImageContainer which contains the current frame
|
||||
// A reference to the VideoFrameContainer which contains the current frame
|
||||
// of video to display.
|
||||
nsRefPtr<ImageContainer> mImageContainer;
|
||||
nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
|
||||
|
||||
// Holds a reference to the first channel we open to the media resource.
|
||||
// Once the decoder is created, control over the channel passes to the
|
||||
@ -642,7 +645,10 @@ protected:
|
||||
PreloadAction mPreloadAction;
|
||||
|
||||
// Size of the media. Updated by the decoder on the main thread if
|
||||
// it changes. Defaults to a width and height of -1 inot set.
|
||||
// it changes. Defaults to a width and height of -1 if not set.
|
||||
// We keep this separate from the intrinsic size stored in the
|
||||
// VideoFrameContainer so that it doesn't change unexpectedly under us
|
||||
// due to decoder activity.
|
||||
nsIntSize mMediaSize;
|
||||
|
||||
// Time that the last timeupdate event was fired. Read/Write from the
|
||||
|
@ -1468,6 +1468,9 @@ nsHTMLMediaElement::~nsHTMLMediaElement()
|
||||
NS_ASSERTION(!mHasSelfReference,
|
||||
"How can we be destroyed if we're still holding a self reference?");
|
||||
|
||||
if (mVideoFrameContainer) {
|
||||
mVideoFrameContainer->ForgetElement();
|
||||
}
|
||||
UnregisterFreezableElement();
|
||||
if (mDecoder) {
|
||||
RemoveMediaElementFromURITable();
|
||||
@ -2471,10 +2474,10 @@ void nsHTMLMediaElement::NotifyAutoplayDataReady()
|
||||
}
|
||||
}
|
||||
|
||||
ImageContainer* nsHTMLMediaElement::GetImageContainer()
|
||||
VideoFrameContainer* nsHTMLMediaElement::GetVideoFrameContainer()
|
||||
{
|
||||
if (mImageContainer)
|
||||
return mImageContainer;
|
||||
if (mVideoFrameContainer)
|
||||
return mVideoFrameContainer;
|
||||
|
||||
// If we have a print surface, this is just a static image so
|
||||
// no image container is required
|
||||
@ -2486,8 +2489,9 @@ ImageContainer* nsHTMLMediaElement::GetImageContainer()
|
||||
if (!video)
|
||||
return nsnull;
|
||||
|
||||
mImageContainer = LayerManager::CreateImageContainer();
|
||||
return mImageContainer;
|
||||
mVideoFrameContainer =
|
||||
new VideoFrameContainer(this, LayerManager::CreateImageContainer());
|
||||
return mVideoFrameContainer;
|
||||
}
|
||||
|
||||
nsresult nsHTMLMediaElement::DispatchAudioAvailableEvent(float* aFrameBuffer,
|
||||
|
@ -209,12 +209,14 @@ NS_IMETHODIMP nsHTMLVideoElement::GetMozPresentedFrames(PRUint32 *aMozPresentedF
|
||||
NS_IMETHODIMP nsHTMLVideoElement::GetMozPaintedFrames(PRUint32 *aMozPaintedFrames)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
*aMozPaintedFrames = (!mDecoder || !GetImageContainer()) ? 0 : GetImageContainer()->GetPaintCount();
|
||||
ImageContainer* container = GetImageContainer();
|
||||
*aMozPaintedFrames = container ? container->GetPaintCount() : 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLVideoElement::GetMozFrameDelay(double *aMozFrameDelay) {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
*aMozFrameDelay = mDecoder ? mDecoder->GetFrameDelay() : 0;
|
||||
VideoFrameContainer* container = GetVideoFrameContainer();
|
||||
*aMozFrameDelay = container ? container->GetFrameDelay() : 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -46,25 +46,27 @@ LIBRARY_NAME = gkconmedia_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
EXPORTS = \
|
||||
nsAudioAvailableEventManager.h \
|
||||
nsMediaDecoder.h \
|
||||
nsMediaStream.h \
|
||||
nsMediaCache.h \
|
||||
nsBuiltinDecoder.h \
|
||||
nsBuiltinDecoderStateMachine.h \
|
||||
nsBuiltinDecoderReader.h \
|
||||
VideoFrameContainer.h \
|
||||
VideoUtils.h \
|
||||
nsAudioAvailableEventManager.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsAudioAvailableEventManager.cpp \
|
||||
nsMediaDecoder.cpp \
|
||||
nsMediaCache.cpp \
|
||||
nsMediaStream.cpp \
|
||||
nsBuiltinDecoder.cpp \
|
||||
nsBuiltinDecoderStateMachine.cpp \
|
||||
nsBuiltinDecoderReader.cpp \
|
||||
VideoFrameContainer.cpp \
|
||||
VideoUtils.cpp \
|
||||
nsAudioAvailableEventManager.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_SYDNEYAUDIO
|
||||
|
93
content/media/VideoFrameContainer.cpp
Normal file
93
content/media/VideoFrameContainer.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/* -*- 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 "VideoFrameContainer.h"
|
||||
|
||||
#include "nsHTMLMediaElement.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsSVGEffects.h"
|
||||
|
||||
using namespace mozilla::layers;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize,
|
||||
Image* aImage,
|
||||
TimeStamp aTargetTime)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (aIntrinsicSize != mIntrinsicSize) {
|
||||
mIntrinsicSize = aIntrinsicSize;
|
||||
mIntrinsicSizeChanged = true;
|
||||
}
|
||||
|
||||
gfxIntSize oldFrameSize = mImageContainer->GetCurrentSize();
|
||||
TimeStamp lastPaintTime = mImageContainer->GetPaintTime();
|
||||
if (!lastPaintTime.IsNull() && !mPaintTarget.IsNull()) {
|
||||
mPaintDelay = lastPaintTime - mPaintTarget;
|
||||
}
|
||||
mImageContainer->SetCurrentImage(aImage);
|
||||
gfxIntSize newFrameSize = mImageContainer->GetCurrentSize();
|
||||
if (oldFrameSize != newFrameSize) {
|
||||
mImageSizeChanged = true;
|
||||
}
|
||||
|
||||
mPaintTarget = aTargetTime;
|
||||
}
|
||||
|
||||
double VideoFrameContainer::GetFrameDelay()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mPaintDelay.ToSeconds();
|
||||
}
|
||||
|
||||
void VideoFrameContainer::Invalidate()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must call on main thread");
|
||||
if (!mElement) {
|
||||
// Element has been destroyed
|
||||
return;
|
||||
}
|
||||
|
||||
nsIFrame* frame = mElement->GetPrimaryFrame();
|
||||
bool invalidateFrame = false;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
// Get mImageContainerSizeChanged while holding the lock.
|
||||
invalidateFrame = mImageSizeChanged;
|
||||
mImageSizeChanged = false;
|
||||
|
||||
if (mIntrinsicSizeChanged) {
|
||||
mElement->UpdateMediaSize(mIntrinsicSize);
|
||||
mIntrinsicSizeChanged = false;
|
||||
|
||||
if (frame) {
|
||||
nsPresContext* presContext = frame->PresContext();
|
||||
nsIPresShell *presShell = presContext->PresShell();
|
||||
presShell->FrameNeedsReflow(frame,
|
||||
nsIPresShell::eStyleChange,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frame) {
|
||||
nsRect contentRect = frame->GetContentRect() - frame->GetPosition();
|
||||
if (invalidateFrame) {
|
||||
frame->Invalidate(contentRect);
|
||||
} else {
|
||||
frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO);
|
||||
}
|
||||
}
|
||||
|
||||
nsSVGEffects::InvalidateDirectRenderingObservers(mElement);
|
||||
}
|
||||
|
||||
}
|
93
content/media/VideoFrameContainer.h
Normal file
93
content/media/VideoFrameContainer.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef VIDEOFRAMECONTAINER_H_
|
||||
#define VIDEOFRAMECONTAINER_H_
|
||||
|
||||
#include "ImageLayers.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "gfxPoint.h"
|
||||
|
||||
class nsHTMLMediaElement;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* This object is used in the decoder backend threads and the main thread
|
||||
* to manage the "current video frame" state. This state includes timing data
|
||||
* and an intrinsic size (see below).
|
||||
* This has to be a thread-safe object since it's accessed by resource decoders
|
||||
* and other off-main-thread components. So we can't put this state in the media
|
||||
* element itself ... well, maybe we could, but it could be risky and/or
|
||||
* confusing.
|
||||
*/
|
||||
class VideoFrameContainer {
|
||||
public:
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
typedef mozilla::layers::Image Image;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoFrameContainer)
|
||||
|
||||
VideoFrameContainer(nsHTMLMediaElement* aElement,
|
||||
already_AddRefed<ImageContainer> aContainer)
|
||||
: mElement(aElement),
|
||||
mImageContainer(aContainer), mMutex("nsVideoFrameContainer"),
|
||||
mIntrinsicSizeChanged(false), mImageSizeChanged(false)
|
||||
{
|
||||
NS_ASSERTION(aElement, "aElement must not be null");
|
||||
NS_ASSERTION(mImageContainer, "aContainer must not be null");
|
||||
}
|
||||
// Call on any thread
|
||||
void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage,
|
||||
TimeStamp aTargetTime);
|
||||
// Time in seconds by which the last painted video frame was late by.
|
||||
// E.g. if the last painted frame should have been painted at time t,
|
||||
// but was actually painted at t+n, this returns n in seconds. Threadsafe.
|
||||
double GetFrameDelay();
|
||||
// Call on main thread
|
||||
void Invalidate();
|
||||
ImageContainer* GetImageContainer() { return mImageContainer; }
|
||||
void ForgetElement() { mElement = nsnull; }
|
||||
|
||||
protected:
|
||||
// Non-addreffed pointer to the element. The element calls ForgetElement
|
||||
// to clear this reference when the element is destroyed.
|
||||
nsHTMLMediaElement* mElement;
|
||||
nsRefPtr<ImageContainer> mImageContainer;
|
||||
|
||||
// mMutex protects all the fields below.
|
||||
Mutex mMutex;
|
||||
// The intrinsic size is the ideal size which we should render the
|
||||
// ImageContainer's current Image at.
|
||||
// This can differ from the Image's actual size when the media resource
|
||||
// specifies that the Image should be stretched to have the correct aspect
|
||||
// ratio.
|
||||
gfxIntSize mIntrinsicSize;
|
||||
// The time at which the current video frame should have been painted.
|
||||
// Access protected by mVideoUpdateLock.
|
||||
TimeStamp mPaintTarget;
|
||||
// The delay between the last video frame being presented and it being
|
||||
// painted. This is time elapsed after mPaintTarget until the most recently
|
||||
// painted frame appeared on screen.
|
||||
TimeDuration mPaintDelay;
|
||||
// True when the intrinsic size has been changed by SetCurrentFrame() since
|
||||
// the last call to Invalidate().
|
||||
// The next call to Invalidate() will recalculate
|
||||
// and update the intrinsic size on the element, request a frame reflow and
|
||||
// then reset this flag.
|
||||
bool mIntrinsicSizeChanged;
|
||||
// True when the Image size has changed since the last time Invalidate() was
|
||||
// called. When set, the next call to Invalidate() will ensure that the
|
||||
// frame is fully invalidated instead of just invalidating for the image change
|
||||
// in the ImageLayer.
|
||||
bool mImageSizeChanged;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* VIDEOFRAMECONTAINER_H_ */
|
@ -137,7 +137,6 @@ bool nsBuiltinDecoder::Init(nsHTMLMediaElement* aElement)
|
||||
return false;
|
||||
|
||||
nsContentUtils::RegisterShutdownObserver(this);
|
||||
mImageContainer = aElement->GetImageContainer();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -514,7 +514,6 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
||||
// The new size must be between 512 and 16384.
|
||||
virtual nsresult RequestFrameBufferLength(PRUint32 aLength);
|
||||
|
||||
public:
|
||||
// Return the current state. Can be called on any thread. If called from
|
||||
// a non-main thread, the decoder monitor must be held.
|
||||
PlayState GetState() {
|
||||
@ -618,7 +617,6 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
||||
// element. Called on the main thread.
|
||||
virtual void NotifyAudioAvailableListener();
|
||||
|
||||
public:
|
||||
// Notifies the element that decoding has failed.
|
||||
void DecodeError();
|
||||
|
||||
|
@ -392,6 +392,7 @@ class nsBuiltinDecoderReader : public nsRunnable {
|
||||
public:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
typedef mozilla::ReentrantMonitorAutoEnter ReentrantMonitorAutoEnter;
|
||||
typedef mozilla::VideoFrameContainer VideoFrameContainer;
|
||||
|
||||
nsBuiltinDecoderReader(nsBuiltinDecoder* aDecoder);
|
||||
~nsBuiltinDecoderReader();
|
||||
|
@ -1908,9 +1908,9 @@ void nsBuiltinDecoderStateMachine::RenderVideoFrame(VideoData* aData,
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<Image> image = aData->mImage;
|
||||
if (image) {
|
||||
mDecoder->SetVideoData(aData->mDisplay, image, aTarget);
|
||||
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
|
||||
if (container) {
|
||||
container->SetCurrentFrame(aData->mDisplay, aData->mImage, aTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,7 @@ public:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
typedef mozilla::TimeDuration TimeDuration;
|
||||
typedef mozilla::VideoFrameContainer VideoFrameContainer;
|
||||
|
||||
nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader, bool aRealTime = false);
|
||||
~nsBuiltinDecoderStateMachine();
|
||||
|
@ -72,13 +72,8 @@ static const PRInt64 CAN_PLAY_THROUGH_MARGIN = 10;
|
||||
|
||||
nsMediaDecoder::nsMediaDecoder() :
|
||||
mElement(nsnull),
|
||||
mRGBWidth(-1),
|
||||
mRGBHeight(-1),
|
||||
mVideoUpdateLock("nsMediaDecoder.mVideoUpdateLock"),
|
||||
mFrameBufferLength(0),
|
||||
mPinnedForSeek(false),
|
||||
mSizeChanged(false),
|
||||
mImageContainerSizeChanged(false),
|
||||
mShuttingDown(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsMediaDecoder);
|
||||
@ -94,6 +89,7 @@ nsMediaDecoder::~nsMediaDecoder()
|
||||
bool nsMediaDecoder::Init(nsHTMLMediaElement* aElement)
|
||||
{
|
||||
mElement = aElement;
|
||||
mVideoFrameContainer = aElement->GetVideoFrameContainer();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -118,47 +114,6 @@ nsresult nsMediaDecoder::RequestFrameBufferLength(PRUint32 aLength)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsMediaDecoder::Invalidate()
|
||||
{
|
||||
if (!mElement)
|
||||
return;
|
||||
|
||||
nsIFrame* frame = mElement->GetPrimaryFrame();
|
||||
bool invalidateFrame = false;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mVideoUpdateLock);
|
||||
|
||||
// Get mImageContainerSizeChanged while holding the lock.
|
||||
invalidateFrame = mImageContainerSizeChanged;
|
||||
mImageContainerSizeChanged = false;
|
||||
|
||||
if (mSizeChanged) {
|
||||
mElement->UpdateMediaSize(nsIntSize(mRGBWidth, mRGBHeight));
|
||||
mSizeChanged = false;
|
||||
|
||||
if (frame) {
|
||||
nsPresContext* presContext = frame->PresContext();
|
||||
nsIPresShell *presShell = presContext->PresShell();
|
||||
presShell->FrameNeedsReflow(frame,
|
||||
nsIPresShell::eStyleChange,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frame) {
|
||||
nsRect contentRect = frame->GetContentRect() - frame->GetPosition();
|
||||
if (invalidateFrame) {
|
||||
frame->Invalidate(contentRect);
|
||||
} else {
|
||||
frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO);
|
||||
}
|
||||
}
|
||||
|
||||
nsSVGEffects::InvalidateDirectRenderingObservers(mElement);
|
||||
}
|
||||
|
||||
static void ProgressCallback(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
nsMediaDecoder* decoder = static_cast<nsMediaDecoder*>(aClosure);
|
||||
@ -224,41 +179,6 @@ void nsMediaDecoder::FireTimeUpdate()
|
||||
mElement->FireTimeUpdate(true);
|
||||
}
|
||||
|
||||
void nsMediaDecoder::SetVideoData(const gfxIntSize& aSize,
|
||||
Image* aImage,
|
||||
TimeStamp aTarget)
|
||||
{
|
||||
MutexAutoLock lock(mVideoUpdateLock);
|
||||
|
||||
if (mRGBWidth != aSize.width || mRGBHeight != aSize.height) {
|
||||
mRGBWidth = aSize.width;
|
||||
mRGBHeight = aSize.height;
|
||||
mSizeChanged = true;
|
||||
}
|
||||
if (mImageContainer && aImage) {
|
||||
gfxIntSize oldFrameSize = mImageContainer->GetCurrentSize();
|
||||
|
||||
TimeStamp paintTime = mImageContainer->GetPaintTime();
|
||||
if (!paintTime.IsNull() && !mPaintTarget.IsNull()) {
|
||||
mPaintDelay = paintTime - mPaintTarget;
|
||||
}
|
||||
|
||||
mImageContainer->SetCurrentImage(aImage);
|
||||
gfxIntSize newFrameSize = mImageContainer->GetCurrentSize();
|
||||
if (oldFrameSize != newFrameSize) {
|
||||
mImageContainerSizeChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
mPaintTarget = aTarget;
|
||||
}
|
||||
|
||||
double nsMediaDecoder::GetFrameDelay()
|
||||
{
|
||||
MutexAutoLock lock(mVideoUpdateLock);
|
||||
return mPaintDelay.ToSeconds();
|
||||
}
|
||||
|
||||
void nsMediaDecoder::PinForSeek()
|
||||
{
|
||||
nsMediaStream* stream = GetStream();
|
||||
|
@ -48,8 +48,8 @@
|
||||
#include "nsITimer.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "VideoFrameContainer.h"
|
||||
|
||||
class nsHTMLMediaElement;
|
||||
class nsMediaStream;
|
||||
@ -67,17 +67,17 @@ static const PRUint32 FRAMEBUFFER_LENGTH_MIN = 512;
|
||||
static const PRUint32 FRAMEBUFFER_LENGTH_MAX = 16384;
|
||||
|
||||
// All methods of nsMediaDecoder must be called from the main thread only
|
||||
// with the exception of GetImageContainer, SetVideoData and GetStatistics,
|
||||
// with the exception of GetVideoFrameContainer and GetStatistics,
|
||||
// which can be called from any thread.
|
||||
class nsMediaDecoder : public nsIObserver
|
||||
{
|
||||
public:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
typedef mozilla::TimeDuration TimeDuration;
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
typedef mozilla::VideoFrameContainer VideoFrameContainer;
|
||||
typedef mozilla::layers::Image Image;
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
typedef mozilla::Mutex Mutex;
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
|
||||
nsMediaDecoder();
|
||||
virtual ~nsMediaDecoder();
|
||||
@ -273,11 +273,6 @@ public:
|
||||
PRUint32& mDecoded;
|
||||
};
|
||||
|
||||
// Time in seconds by which the last painted video frame was late by.
|
||||
// E.g. if the last painted frame should have been painted at time t,
|
||||
// but was actually painted at t+n, this returns n in seconds. Threadsafe.
|
||||
double GetFrameDelay();
|
||||
|
||||
// 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
|
||||
@ -306,7 +301,12 @@ public:
|
||||
virtual void SetEndTime(double aTime) = 0;
|
||||
|
||||
// Invalidate the frame.
|
||||
virtual void Invalidate();
|
||||
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
|
||||
@ -375,18 +375,6 @@ public:
|
||||
// their nsMediaStream.
|
||||
virtual void MoveLoadsToBackground()=0;
|
||||
|
||||
// Gets the image container for the media element. Will return null if
|
||||
// the element is not a video element. This can be called from any
|
||||
// thread; ImageContainers can be used from any thread.
|
||||
ImageContainer* GetImageContainer() { return mImageContainer; }
|
||||
|
||||
// Set the video width, height, pixel aspect ratio, current image and
|
||||
// target paint time of the next video frame to be displayed.
|
||||
// Ownership of the image is transferred to the layers subsystem.
|
||||
void SetVideoData(const gfxIntSize& aSize,
|
||||
Image* aImage,
|
||||
TimeStamp aTarget);
|
||||
|
||||
// Constructs the time ranges representing what segments of the media
|
||||
// are buffered and playable.
|
||||
virtual nsresult GetBuffered(nsTimeRanges* aBuffered) = 0;
|
||||
@ -400,6 +388,12 @@ public:
|
||||
virtual PRInt64 VideoQueueMemoryInUse() = 0;
|
||||
virtual PRInt64 AudioQueueMemoryInUse() = 0;
|
||||
|
||||
VideoFrameContainer* GetVideoFrameContainer() { return mVideoFrameContainer; }
|
||||
ImageContainer* GetImageContainer()
|
||||
{
|
||||
return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer() : nsnull;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Start timer to update download progress information.
|
||||
@ -422,22 +416,10 @@ protected:
|
||||
// The decoder does not add a reference the element.
|
||||
nsHTMLMediaElement* mElement;
|
||||
|
||||
PRInt32 mRGBWidth;
|
||||
PRInt32 mRGBHeight;
|
||||
|
||||
// Counters related to decode and presentation of frames.
|
||||
FrameStatistics mFrameStats;
|
||||
|
||||
// The time at which the current video frame should have been painted.
|
||||
// Access protected by mVideoUpdateLock.
|
||||
TimeStamp mPaintTarget;
|
||||
|
||||
// The delay between the last video frame being presented and it being
|
||||
// painted. This is time elapsed after mPaintTarget until the most recently
|
||||
// painted frame appeared on screen. Access protected by mVideoUpdateLock.
|
||||
TimeDuration mPaintDelay;
|
||||
|
||||
nsRefPtr<ImageContainer> mImageContainer;
|
||||
nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
|
||||
|
||||
// Time that the last progress event was fired. Read/Write from the
|
||||
// main thread only.
|
||||
@ -450,17 +432,6 @@ protected:
|
||||
// more data is received. Read/Write from the main thread only.
|
||||
TimeStamp mDataTime;
|
||||
|
||||
// Lock around the video RGB, width and size data. This
|
||||
// is used in the decoder backend threads and the main thread
|
||||
// to ensure that repainting the video does not use these
|
||||
// values while they are out of sync (width changed but
|
||||
// not height yet, etc).
|
||||
// Backends that are updating the height, width or writing
|
||||
// to the RGB buffer must obtain this lock first to ensure that
|
||||
// the video element does not use video data or sizes that are
|
||||
// in the midst of being changed.
|
||||
Mutex mVideoUpdateLock;
|
||||
|
||||
// The framebuffer size to use for audioavailable events.
|
||||
PRUint32 mFrameBufferLength;
|
||||
|
||||
@ -468,20 +439,6 @@ protected:
|
||||
// while seeking.
|
||||
bool mPinnedForSeek;
|
||||
|
||||
// Set to true when the video width, height or pixel aspect ratio is
|
||||
// changed by SetVideoData(). The next call to Invalidate() will recalculate
|
||||
// and update the intrinsic size on the element, request a frame reflow and
|
||||
// then reset this flag.
|
||||
bool mSizeChanged;
|
||||
|
||||
// Set to true in SetVideoData() if the new image has a different size
|
||||
// than the current image. The image size is also affected by transforms
|
||||
// so this can be true even if mSizeChanged is false, for example when
|
||||
// zooming. The next call to Invalidate() will call nsIFrame::Invalidate
|
||||
// when this flag is set, rather than just InvalidateLayer, and then reset
|
||||
// this flag.
|
||||
bool mImageContainerSizeChanged;
|
||||
|
||||
// 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.
|
||||
|
@ -266,9 +266,12 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
mInfo.mDisplay = displaySize;
|
||||
mPicture = picture;
|
||||
|
||||
mDecoder->SetVideoData(gfxIntSize(displaySize.width, displaySize.height),
|
||||
nsnull,
|
||||
TimeStamp::Now());
|
||||
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
|
||||
if (container) {
|
||||
container->SetCurrentFrame(gfxIntSize(displaySize.width, displaySize.height),
|
||||
nsnull,
|
||||
TimeStamp::Now());
|
||||
}
|
||||
|
||||
// Copy Theora info data for time computations on other threads.
|
||||
memcpy(&mTheoraInfo, &mTheoraState->mInfo, sizeof(mTheoraInfo));
|
||||
|
@ -263,6 +263,7 @@ public:
|
||||
* been created by this ImageContainer.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* aImage can be null. While it's null, nothing will be painted.
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user