On x86 compilers without fastcall, simulate it when invoking traces and un-simulate...
[wine-gecko.git] / content / media / video / src / nsVideoDecoder.cpp
blob4f8124585aaca6632c84b5ede3be4d1115a71ffc
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 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: ML 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla code.
18 * The Initial Developer of the Original Code is the Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Chris Double <chris.double@double.co.nz>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
38 #include "prlog.h"
39 #include "prmem.h"
40 #include "nsIFrame.h"
41 #include "nsIDocument.h"
42 #include "nsThreadUtils.h"
43 #include "nsIDOMHTMLMediaElement.h"
44 #include "nsNetUtil.h"
45 #include "nsHTMLMediaElement.h"
46 #include "nsIObserver.h"
47 #include "nsIObserverService.h"
48 #include "nsAutoLock.h"
49 #include "nsIRenderingContext.h"
50 #include "gfxContext.h"
51 #include "gfxImageSurface.h"
52 #include "nsPresContext.h"
53 #include "nsVideoDecoder.h"
55 #ifdef PR_LOGGING
56 // Logging object for decoder
57 PRLogModuleInfo* gVideoDecoderLog = nsnull;
58 #endif
60 nsVideoDecoder::nsVideoDecoder() :
61 mElement(0),
62 mRGBWidth(-1),
63 mRGBHeight(-1),
64 mSizeChanged(PR_FALSE),
65 mVideoUpdateLock(nsnull),
66 mFramerate(0.0)
70 PRBool nsVideoDecoder::Init()
72 mVideoUpdateLock = PR_NewLock();
74 return mVideoUpdateLock != nsnull;
77 void nsVideoDecoder::Shutdown()
79 if (mVideoUpdateLock) {
80 PR_DestroyLock(mVideoUpdateLock);
81 mVideoUpdateLock = nsnull;
86 nsresult nsVideoDecoder::InitLogger()
88 #ifdef PR_LOGGING
89 gVideoDecoderLog = PR_NewLogModule("nsVideoDecoder");
90 #endif
91 return NS_OK;
94 static void InvalidateCallback(nsITimer* aTimer, void* aClosure)
96 nsVideoDecoder* decoder = static_cast<nsVideoDecoder*>(aClosure);
97 decoder->Invalidate();
100 nsresult nsVideoDecoder::StartInvalidating(double aFramerate)
102 nsresult rv = NS_OK;
104 if (!mInvalidateTimer && aFramerate > 0.0) {
105 mInvalidateTimer = do_CreateInstance("@mozilla.org/timer;1");
106 rv = mInvalidateTimer->InitWithFuncCallback(InvalidateCallback,
107 this,
108 static_cast<PRInt32>(1000.0/aFramerate),
109 nsITimer::TYPE_REPEATING_PRECISE);
111 return rv;
114 void nsVideoDecoder::StopInvalidating()
116 if (mInvalidateTimer) {
117 mInvalidateTimer->Cancel();
118 mInvalidateTimer = nsnull;
122 void nsVideoDecoder::Invalidate()
124 if (!mElement)
125 return;
127 nsIFrame* frame = mElement->GetPrimaryFrame();
128 if (!frame)
129 return;
132 nsAutoLock lock(mVideoUpdateLock);
133 if (mSizeChanged) {
134 mSizeChanged = PR_FALSE;
135 nsPresContext* presContext = frame->PresContext();
136 nsIPresShell *presShell = presContext->PresShell();
137 presShell->FrameNeedsReflow(frame,
138 nsIPresShell::eStyleChange,
139 NS_FRAME_IS_DIRTY);
142 nsRect r(nsPoint(0,0), frame->GetSize());
143 frame->Invalidate(r, PR_FALSE);
146 static void ProgressCallback(nsITimer* aTimer, void* aClosure)
148 nsVideoDecoder* decoder = static_cast<nsVideoDecoder*>(aClosure);
149 decoder->Progress();
152 void nsVideoDecoder::Progress()
154 if (!mElement)
155 return;
157 mElement->DispatchProgressEvent(NS_LITERAL_STRING("progress"));
160 nsresult nsVideoDecoder::StartProgress()
162 nsresult rv = NS_OK;
164 if (!mProgressTimer) {
165 mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
166 rv = mProgressTimer->InitWithFuncCallback(ProgressCallback,
167 this,
168 350, // Number of milliseconds defined in spec
169 nsITimer::TYPE_REPEATING_PRECISE);
171 return rv;
174 nsresult nsVideoDecoder::StopProgress()
176 nsresult rv = NS_OK;
177 if (mProgressTimer) {
178 rv = mProgressTimer->Cancel();
179 mProgressTimer = nsnull;
181 return rv;
184 void nsVideoDecoder::SetRGBData(PRInt32 aWidth, PRInt32 aHeight, double aFramerate, unsigned char* aRGBBuffer)
186 if (mRGBWidth != aWidth || mRGBHeight != aHeight) {
187 mRGBWidth = aWidth;
188 mRGBHeight = aHeight;
189 mSizeChanged = PR_TRUE;
190 // Delete buffer so we'll reallocate it
191 mRGB = nsnull;
193 mFramerate = aFramerate;
195 if (!mRGB)
196 mRGB = new unsigned char[aWidth * aHeight * 4];
197 if (mRGB && aRGBBuffer) {
198 memcpy(mRGB.get(), aRGBBuffer, aWidth*aHeight*4);
202 void nsVideoDecoder::Paint(gfxContext* aContext, const gfxRect& aRect)
204 nsAutoLock lock(mVideoUpdateLock);
206 if (!mRGB)
207 return;
209 if (mFramerate > 0.0) {
210 StartInvalidating(mFramerate);
213 /* Create a surface backed by the RGB */
214 nsRefPtr<gfxASurface> surface =
215 new gfxImageSurface(mRGB,
216 gfxIntSize(mRGBWidth, mRGBHeight),
217 mRGBWidth * 4,
218 gfxASurface::ImageFormatARGB32);
220 if (!surface)
221 return;
223 nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
224 if (!pat)
225 return;
227 // Make the source image fill the rectangle completely
228 pat->SetMatrix(gfxMatrix().Scale(mRGBWidth/aRect.Width(), mRGBHeight/aRect.Height()));
230 /* Draw RGB surface onto frame */
231 aContext->NewPath();
232 aContext->PixelSnappedRectangleAndSetPattern(aRect, pat);
233 aContext->Fill();
235 #ifdef DEBUG_FRAME_RATE
237 // Output frame rate
238 static double last = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
239 double now = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
240 static int count = 0;
241 count++;
242 if (now-last > 10.0) {
243 LOG(PR_LOG_DEBUG, ("Paint Frame Rate = %f (should be %f)\n", (float)count / (float)(now-last), mFramerate));
244 count = 0;
245 last = double(PR_IntervalToMilliseconds(PR_IntervalNow()))/1000.0;
248 #endif
251 void nsVideoDecoder::ElementAvailable(nsHTMLMediaElement* anElement)
253 mElement = anElement;
256 void nsVideoDecoder::ElementUnavailable()
258 mElement = nsnull;