2012-02-14 20:35:01 -08:00
|
|
|
/* -*- 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"
|
2012-08-20 21:06:46 -07:00
|
|
|
#include "ImageContainer.h"
|
2012-02-14 20:35:01 -08:00
|
|
|
|
|
|
|
using namespace mozilla::layers;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2012-08-20 21:06:46 -07:00
|
|
|
VideoFrameContainer::VideoFrameContainer(nsHTMLMediaElement* aElement,
|
|
|
|
already_AddRefed<ImageContainer> aContainer)
|
|
|
|
: mElement(aElement),
|
|
|
|
mImageContainer(aContainer), mMutex("nsVideoFrameContainer"),
|
|
|
|
mIntrinsicSizeChanged(false), mImageSizeChanged(false),
|
|
|
|
mNeedInvalidation(true)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aElement, "aElement must not be null");
|
|
|
|
NS_ASSERTION(mImageContainer, "aContainer must not be null");
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoFrameContainer::~VideoFrameContainer()
|
|
|
|
{}
|
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
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;
|
|
|
|
}
|
2012-09-26 21:33:43 -07:00
|
|
|
|
|
|
|
// When using the OMX decoder, destruction of the current image can indirectly
|
|
|
|
// block on main thread I/O. If we let this happen while holding onto
|
|
|
|
// |mImageContainer|'s lock, then when the main thread then tries to
|
|
|
|
// composite it can then block on |mImageContainer|'s lock, causing a
|
|
|
|
// deadlock. We use this hack to defer the destruction of the current image
|
|
|
|
// until it is safe.
|
|
|
|
nsRefPtr<Image> kungFuDeathGrip;
|
|
|
|
kungFuDeathGrip = mImageContainer->LockCurrentImage();
|
|
|
|
mImageContainer->UnlockCurrentImage();
|
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
mImageContainer->SetCurrentImage(aImage);
|
|
|
|
gfxIntSize newFrameSize = mImageContainer->GetCurrentSize();
|
|
|
|
if (oldFrameSize != newFrameSize) {
|
|
|
|
mImageSizeChanged = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
mPaintTarget = aTargetTime;
|
|
|
|
}
|
|
|
|
|
2012-09-26 21:33:43 -07:00
|
|
|
void VideoFrameContainer::ClearCurrentFrame()
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
|
|
|
|
// See comment in SetCurrentFrame for the reasoning behind
|
|
|
|
// using a kungFuDeathGrip here.
|
|
|
|
nsRefPtr<Image> kungFuDeathGrip;
|
|
|
|
kungFuDeathGrip = mImageContainer->LockCurrentImage();
|
|
|
|
mImageContainer->UnlockCurrentImage();
|
|
|
|
|
|
|
|
mImageContainer->SetCurrentImage(nullptr);
|
|
|
|
}
|
|
|
|
|
2012-08-20 21:06:46 -07:00
|
|
|
ImageContainer* VideoFrameContainer::GetImageContainer() {
|
|
|
|
return mImageContainer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
double VideoFrameContainer::GetFrameDelay()
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
return mPaintDelay.ToSeconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoFrameContainer::Invalidate()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Must call on main thread");
|
2012-08-10 08:42:53 -07:00
|
|
|
|
|
|
|
if (!mNeedInvalidation) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (mImageContainer && mImageContainer->IsAsync()) {
|
|
|
|
mNeedInvalidation = false;
|
|
|
|
}
|
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
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) {
|
2012-09-27 08:34:46 -07:00
|
|
|
nsRect contentRect = frame->GetContentRect() - frame->GetPosition();
|
2012-02-14 20:35:01 -08:00
|
|
|
if (invalidateFrame) {
|
2012-09-27 08:34:46 -07:00
|
|
|
frame->Invalidate(contentRect);
|
2012-02-14 20:35:01 -08:00
|
|
|
} else {
|
2012-09-27 08:34:46 -07:00
|
|
|
frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO);
|
2012-02-14 20:35:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(mElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|