1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/VideoFrameContainer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,152 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "VideoFrameContainer.h" 1.11 + 1.12 +#include "mozilla/dom/HTMLMediaElement.h" 1.13 +#include "nsIFrame.h" 1.14 +#include "nsDisplayList.h" 1.15 +#include "nsSVGEffects.h" 1.16 +#include "ImageContainer.h" 1.17 + 1.18 +using namespace mozilla::layers; 1.19 + 1.20 +namespace mozilla { 1.21 + 1.22 +VideoFrameContainer::VideoFrameContainer(dom::HTMLMediaElement* aElement, 1.23 + already_AddRefed<ImageContainer> aContainer) 1.24 + : mElement(aElement), 1.25 + mImageContainer(aContainer), mMutex("nsVideoFrameContainer"), 1.26 + mIntrinsicSizeChanged(false), mImageSizeChanged(false) 1.27 +{ 1.28 + NS_ASSERTION(aElement, "aElement must not be null"); 1.29 + NS_ASSERTION(mImageContainer, "aContainer must not be null"); 1.30 +} 1.31 + 1.32 +VideoFrameContainer::~VideoFrameContainer() 1.33 +{} 1.34 + 1.35 +void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, 1.36 + Image* aImage, 1.37 + TimeStamp aTargetTime) 1.38 +{ 1.39 + MutexAutoLock lock(mMutex); 1.40 + 1.41 + if (aIntrinsicSize != mIntrinsicSize) { 1.42 + mIntrinsicSize = aIntrinsicSize; 1.43 + mIntrinsicSizeChanged = true; 1.44 + } 1.45 + 1.46 + gfx::IntSize oldFrameSize = mImageContainer->GetCurrentSize(); 1.47 + TimeStamp lastPaintTime = mImageContainer->GetPaintTime(); 1.48 + if (!lastPaintTime.IsNull() && !mPaintTarget.IsNull()) { 1.49 + mPaintDelay = lastPaintTime - mPaintTarget; 1.50 + } 1.51 + 1.52 + // When using the OMX decoder, destruction of the current image can indirectly 1.53 + // block on main thread I/O. If we let this happen while holding onto 1.54 + // |mImageContainer|'s lock, then when the main thread then tries to 1.55 + // composite it can then block on |mImageContainer|'s lock, causing a 1.56 + // deadlock. We use this hack to defer the destruction of the current image 1.57 + // until it is safe. 1.58 + nsRefPtr<Image> kungFuDeathGrip; 1.59 + kungFuDeathGrip = mImageContainer->LockCurrentImage(); 1.60 + mImageContainer->UnlockCurrentImage(); 1.61 + 1.62 + mImageContainer->SetCurrentImage(aImage); 1.63 + gfx::IntSize newFrameSize = mImageContainer->GetCurrentSize(); 1.64 + if (oldFrameSize != newFrameSize) { 1.65 + mImageSizeChanged = true; 1.66 + } 1.67 + 1.68 + mPaintTarget = aTargetTime; 1.69 +} 1.70 + 1.71 +void VideoFrameContainer::Reset() 1.72 +{ 1.73 + ClearCurrentFrame(true); 1.74 + Invalidate(); 1.75 + mIntrinsicSize = gfxIntSize(-1, -1); 1.76 + mPaintDelay = mozilla::TimeDuration(); 1.77 + mPaintTarget = mozilla::TimeStamp(); 1.78 + mImageContainer->ResetPaintCount(); 1.79 +} 1.80 + 1.81 +void VideoFrameContainer::ClearCurrentFrame(bool aResetSize) 1.82 +{ 1.83 + MutexAutoLock lock(mMutex); 1.84 + 1.85 + // See comment in SetCurrentFrame for the reasoning behind 1.86 + // using a kungFuDeathGrip here. 1.87 + nsRefPtr<Image> kungFuDeathGrip; 1.88 + kungFuDeathGrip = mImageContainer->LockCurrentImage(); 1.89 + mImageContainer->UnlockCurrentImage(); 1.90 + 1.91 + mImageContainer->ClearAllImages(); 1.92 + mImageSizeChanged = aResetSize; 1.93 +} 1.94 + 1.95 +ImageContainer* VideoFrameContainer::GetImageContainer() { 1.96 + return mImageContainer; 1.97 +} 1.98 + 1.99 + 1.100 +double VideoFrameContainer::GetFrameDelay() 1.101 +{ 1.102 + MutexAutoLock lock(mMutex); 1.103 + return mPaintDelay.ToSeconds(); 1.104 +} 1.105 + 1.106 +void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags) 1.107 +{ 1.108 + NS_ASSERTION(NS_IsMainThread(), "Must call on main thread"); 1.109 + 1.110 + if (!mElement) { 1.111 + // Element has been destroyed 1.112 + return; 1.113 + } 1.114 + 1.115 + nsIFrame* frame = mElement->GetPrimaryFrame(); 1.116 + bool invalidateFrame = false; 1.117 + 1.118 + { 1.119 + MutexAutoLock lock(mMutex); 1.120 + 1.121 + // Get mImageContainerSizeChanged while holding the lock. 1.122 + invalidateFrame = mImageSizeChanged; 1.123 + mImageSizeChanged = false; 1.124 + 1.125 + if (mIntrinsicSizeChanged) { 1.126 + mElement->UpdateMediaSize(mIntrinsicSize); 1.127 + mIntrinsicSizeChanged = false; 1.128 + 1.129 + if (frame) { 1.130 + nsPresContext* presContext = frame->PresContext(); 1.131 + nsIPresShell *presShell = presContext->PresShell(); 1.132 + presShell->FrameNeedsReflow(frame, 1.133 + nsIPresShell::eStyleChange, 1.134 + NS_FRAME_IS_DIRTY); 1.135 + } 1.136 + } 1.137 + } 1.138 + 1.139 + bool asyncInvalidate = mImageContainer && 1.140 + mImageContainer->IsAsync() && 1.141 + !(aFlags & INVALIDATE_FORCE); 1.142 + 1.143 + if (frame) { 1.144 + if (invalidateFrame) { 1.145 + frame->InvalidateFrame(); 1.146 + } else { 1.147 + frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO, nullptr, 1.148 + asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0); 1.149 + } 1.150 + } 1.151 + 1.152 + nsSVGEffects::InvalidateDirectRenderingObservers(mElement); 1.153 +} 1.154 + 1.155 +}