|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "VideoFrameContainer.h" |
|
8 |
|
9 #include "mozilla/dom/HTMLMediaElement.h" |
|
10 #include "nsIFrame.h" |
|
11 #include "nsDisplayList.h" |
|
12 #include "nsSVGEffects.h" |
|
13 #include "ImageContainer.h" |
|
14 |
|
15 using namespace mozilla::layers; |
|
16 |
|
17 namespace mozilla { |
|
18 |
|
19 VideoFrameContainer::VideoFrameContainer(dom::HTMLMediaElement* aElement, |
|
20 already_AddRefed<ImageContainer> aContainer) |
|
21 : mElement(aElement), |
|
22 mImageContainer(aContainer), mMutex("nsVideoFrameContainer"), |
|
23 mIntrinsicSizeChanged(false), mImageSizeChanged(false) |
|
24 { |
|
25 NS_ASSERTION(aElement, "aElement must not be null"); |
|
26 NS_ASSERTION(mImageContainer, "aContainer must not be null"); |
|
27 } |
|
28 |
|
29 VideoFrameContainer::~VideoFrameContainer() |
|
30 {} |
|
31 |
|
32 void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, |
|
33 Image* aImage, |
|
34 TimeStamp aTargetTime) |
|
35 { |
|
36 MutexAutoLock lock(mMutex); |
|
37 |
|
38 if (aIntrinsicSize != mIntrinsicSize) { |
|
39 mIntrinsicSize = aIntrinsicSize; |
|
40 mIntrinsicSizeChanged = true; |
|
41 } |
|
42 |
|
43 gfx::IntSize oldFrameSize = mImageContainer->GetCurrentSize(); |
|
44 TimeStamp lastPaintTime = mImageContainer->GetPaintTime(); |
|
45 if (!lastPaintTime.IsNull() && !mPaintTarget.IsNull()) { |
|
46 mPaintDelay = lastPaintTime - mPaintTarget; |
|
47 } |
|
48 |
|
49 // When using the OMX decoder, destruction of the current image can indirectly |
|
50 // block on main thread I/O. If we let this happen while holding onto |
|
51 // |mImageContainer|'s lock, then when the main thread then tries to |
|
52 // composite it can then block on |mImageContainer|'s lock, causing a |
|
53 // deadlock. We use this hack to defer the destruction of the current image |
|
54 // until it is safe. |
|
55 nsRefPtr<Image> kungFuDeathGrip; |
|
56 kungFuDeathGrip = mImageContainer->LockCurrentImage(); |
|
57 mImageContainer->UnlockCurrentImage(); |
|
58 |
|
59 mImageContainer->SetCurrentImage(aImage); |
|
60 gfx::IntSize newFrameSize = mImageContainer->GetCurrentSize(); |
|
61 if (oldFrameSize != newFrameSize) { |
|
62 mImageSizeChanged = true; |
|
63 } |
|
64 |
|
65 mPaintTarget = aTargetTime; |
|
66 } |
|
67 |
|
68 void VideoFrameContainer::Reset() |
|
69 { |
|
70 ClearCurrentFrame(true); |
|
71 Invalidate(); |
|
72 mIntrinsicSize = gfxIntSize(-1, -1); |
|
73 mPaintDelay = mozilla::TimeDuration(); |
|
74 mPaintTarget = mozilla::TimeStamp(); |
|
75 mImageContainer->ResetPaintCount(); |
|
76 } |
|
77 |
|
78 void VideoFrameContainer::ClearCurrentFrame(bool aResetSize) |
|
79 { |
|
80 MutexAutoLock lock(mMutex); |
|
81 |
|
82 // See comment in SetCurrentFrame for the reasoning behind |
|
83 // using a kungFuDeathGrip here. |
|
84 nsRefPtr<Image> kungFuDeathGrip; |
|
85 kungFuDeathGrip = mImageContainer->LockCurrentImage(); |
|
86 mImageContainer->UnlockCurrentImage(); |
|
87 |
|
88 mImageContainer->ClearAllImages(); |
|
89 mImageSizeChanged = aResetSize; |
|
90 } |
|
91 |
|
92 ImageContainer* VideoFrameContainer::GetImageContainer() { |
|
93 return mImageContainer; |
|
94 } |
|
95 |
|
96 |
|
97 double VideoFrameContainer::GetFrameDelay() |
|
98 { |
|
99 MutexAutoLock lock(mMutex); |
|
100 return mPaintDelay.ToSeconds(); |
|
101 } |
|
102 |
|
103 void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags) |
|
104 { |
|
105 NS_ASSERTION(NS_IsMainThread(), "Must call on main thread"); |
|
106 |
|
107 if (!mElement) { |
|
108 // Element has been destroyed |
|
109 return; |
|
110 } |
|
111 |
|
112 nsIFrame* frame = mElement->GetPrimaryFrame(); |
|
113 bool invalidateFrame = false; |
|
114 |
|
115 { |
|
116 MutexAutoLock lock(mMutex); |
|
117 |
|
118 // Get mImageContainerSizeChanged while holding the lock. |
|
119 invalidateFrame = mImageSizeChanged; |
|
120 mImageSizeChanged = false; |
|
121 |
|
122 if (mIntrinsicSizeChanged) { |
|
123 mElement->UpdateMediaSize(mIntrinsicSize); |
|
124 mIntrinsicSizeChanged = false; |
|
125 |
|
126 if (frame) { |
|
127 nsPresContext* presContext = frame->PresContext(); |
|
128 nsIPresShell *presShell = presContext->PresShell(); |
|
129 presShell->FrameNeedsReflow(frame, |
|
130 nsIPresShell::eStyleChange, |
|
131 NS_FRAME_IS_DIRTY); |
|
132 } |
|
133 } |
|
134 } |
|
135 |
|
136 bool asyncInvalidate = mImageContainer && |
|
137 mImageContainer->IsAsync() && |
|
138 !(aFlags & INVALIDATE_FORCE); |
|
139 |
|
140 if (frame) { |
|
141 if (invalidateFrame) { |
|
142 frame->InvalidateFrame(); |
|
143 } else { |
|
144 frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO, nullptr, |
|
145 asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0); |
|
146 } |
|
147 } |
|
148 |
|
149 nsSVGEffects::InvalidateDirectRenderingObservers(mElement); |
|
150 } |
|
151 |
|
152 } |