04806892d7c93bdacd9070f9abde5b80bdf49d6a
[WebKit-https.git] / WebCore / platform / graphics / win / MediaPlayerPrivateQuickTimeWin.cpp
1 /*\r
2  * Copyright (C) 2007 Apple Inc. All rights reserved.\r
3  *\r
4  * Redistribution and use in source and binary forms, with or without\r
5  * modification, are permitted provided that the following conditions\r
6  * are met:\r
7  * 1. Redistributions of source code must retain the above copyright\r
8  *    notice, this list of conditions and the following disclaimer.\r
9  * 2. Redistributions in binary form must reproduce the above copyright\r
10  *    notice, this list of conditions and the following disclaimer in the\r
11  *    documentation and/or other materials provided with the distribution.\r
12  *\r
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY\r
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR\r
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\r
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \r
24  */\r
25 \r
26 #include "config.h"\r
27 \r
28 #if ENABLE(VIDEO)\r
29 #include "MediaPlayerPrivateQuickTimeWin.h"\r
30 \r
31 #include "DeprecatedString.h"\r
32 #include "GraphicsContext.h"\r
33 #include "KURL.h"\r
34 #include "QTMovieWin.h"\r
35 #include "ScrollView.h"\r
36 #include <wtf/MathExtras.h>\r
37 \r
38 using namespace std;\r
39 \r
40 namespace WebCore {\r
41 \r
42 static const double endPointTimerInterval = 0.020;\r
43     \r
44 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)\r
45     : m_player(player)\r
46     , m_seekTo(-1)\r
47     , m_endTime(numeric_limits<float>::infinity())\r
48     , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)\r
49     , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)\r
50     , m_networkState(MediaPlayer::Empty)\r
51     , m_readyState(MediaPlayer::DataUnavailable)\r
52     , m_startedPlaying(false)\r
53     , m_isStreaming(false)\r
54 {\r
55 }\r
56 \r
57 MediaPlayerPrivate::~MediaPlayerPrivate()\r
58 {\r
59 }\r
60 \r
61 void MediaPlayerPrivate::load(const String& url)\r
62 {\r
63     if (!QTMovieWin::initializeQuickTime()) {\r
64         m_networkState = MediaPlayer::LoadFailed;\r
65         m_player->networkStateChanged();\r
66         return;\r
67     }\r
68 \r
69     if (m_networkState != MediaPlayer::Loading) {\r
70         m_networkState = MediaPlayer::Loading;\r
71         m_player->networkStateChanged();\r
72     }\r
73     if (m_readyState != MediaPlayer::DataUnavailable) {\r
74         m_readyState = MediaPlayer::DataUnavailable;\r
75         m_player->readyStateChanged();\r
76     }\r
77     cancelSeek();\r
78     m_endPointTimer.stop();\r
79 \r
80     m_qtMovie.set(new QTMovieWin(this));\r
81     m_qtMovie->load(url.characters(), url.length());\r
82     m_qtMovie->setMuted(m_player->m_muted);\r
83     m_qtMovie->setVolume(m_player->m_volume);\r
84     m_qtMovie->setVisible(m_player->m_visible);\r
85 }\r
86 \r
87 void MediaPlayerPrivate::play()\r
88 {\r
89     if (!m_qtMovie)\r
90         return;\r
91     m_startedPlaying = true;\r
92 \r
93     m_qtMovie->play();\r
94     startEndPointTimerIfNeeded();\r
95 }\r
96 \r
97 void MediaPlayerPrivate::pause()\r
98 {\r
99     if (!m_qtMovie)\r
100         return;\r
101     m_startedPlaying = false;\r
102     m_qtMovie->pause();\r
103     m_endPointTimer.stop();\r
104 }\r
105 \r
106 float MediaPlayerPrivate::duration() const\r
107 {\r
108     if (!m_qtMovie)\r
109         return 0;\r
110     return m_qtMovie->duration();\r
111 }\r
112 \r
113 float MediaPlayerPrivate::currentTime() const\r
114 {\r
115     if (!m_qtMovie)\r
116         return 0;\r
117     return min(m_qtMovie->currentTime(), m_endTime);\r
118 }\r
119 \r
120 void MediaPlayerPrivate::seek(float time)\r
121 {\r
122     cancelSeek();\r
123     \r
124     if (!m_qtMovie)\r
125         return;\r
126     \r
127     if (time > duration())\r
128         time = duration();\r
129     \r
130     m_seekTo = time;\r
131     if (maxTimeLoaded() >= m_seekTo)\r
132         doSeek();\r
133     else \r
134         m_seekTimer.start(0, 0.5f);\r
135 }\r
136     \r
137 void MediaPlayerPrivate::doSeek() \r
138 {\r
139     float oldRate = m_qtMovie->rate();\r
140     m_qtMovie->setRate(0);\r
141     m_qtMovie->setCurrentTime(m_seekTo);\r
142     float timeAfterSeek = currentTime();\r
143     // restore playback only if not at end, othewise QTMovie will loop\r
144     if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)\r
145         m_qtMovie->setRate(oldRate);\r
146     cancelSeek();\r
147 }\r
148 \r
149 void MediaPlayerPrivate::cancelSeek()\r
150 {\r
151     m_seekTo = -1;\r
152     m_seekTimer.stop();\r
153 }\r
154 \r
155 void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)\r
156 {        \r
157     if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {\r
158         cancelSeek();\r
159         updateStates();\r
160         m_player->timeChanged(); \r
161         return;\r
162     } \r
163     \r
164     if (maxTimeLoaded() >= m_seekTo)\r
165         doSeek();\r
166     else {\r
167         MediaPlayer::NetworkState state = networkState();\r
168         if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {\r
169             cancelSeek();\r
170             updateStates();\r
171             m_player->timeChanged();\r
172         }\r
173     }\r
174 }\r
175 \r
176 void MediaPlayerPrivate::setEndTime(float time)\r
177 {\r
178     m_endTime = time;\r
179     startEndPointTimerIfNeeded();\r
180 }\r
181 \r
182 void MediaPlayerPrivate::startEndPointTimerIfNeeded()\r
183 {\r
184     if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())\r
185         m_endPointTimer.startRepeating(endPointTimerInterval);\r
186 }\r
187 \r
188 void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)\r
189 {\r
190     float time = currentTime();\r
191     if (time >= m_endTime) {\r
192         pause();\r
193         didEnd();\r
194     }\r
195 }\r
196 \r
197 bool MediaPlayerPrivate::paused() const\r
198 {\r
199     if (!m_qtMovie)\r
200         return true;\r
201     return m_qtMovie->rate() == 0.0f;\r
202 }\r
203 \r
204 bool MediaPlayerPrivate::seeking() const\r
205 {\r
206     if (!m_qtMovie)\r
207         return false;\r
208     return m_seekTo >= 0;\r
209 }\r
210 \r
211 IntSize MediaPlayerPrivate::naturalSize() const\r
212 {\r
213     if (!m_qtMovie)\r
214         return IntSize();\r
215     int width;\r
216     int height;\r
217     m_qtMovie->getNaturalSize(width, height);\r
218     return IntSize(width, height);\r
219 }\r
220 \r
221 bool MediaPlayerPrivate::hasVideo() const\r
222 {\r
223     // This is not used at the moment\r
224     return true;\r
225 }\r
226 \r
227 void MediaPlayerPrivate::setVolume(float volume)\r
228 {\r
229     if (!m_qtMovie)\r
230         return;\r
231     m_qtMovie->setVolume(volume);\r
232 }\r
233 \r
234 void MediaPlayerPrivate::setMuted(bool b)\r
235 {\r
236     if (!m_qtMovie)\r
237         return;\r
238     m_qtMovie->setMuted(b);\r
239 }\r
240 \r
241 void MediaPlayerPrivate::setRate(float rate)\r
242 {\r
243     if (!m_qtMovie)\r
244         return;\r
245     if (!paused())\r
246         m_qtMovie->setRate(rate);\r
247 }\r
248 \r
249 int MediaPlayerPrivate::dataRate() const\r
250 {\r
251     // This is not used at the moment\r
252     return 0;\r
253 }\r
254 \r
255 float MediaPlayerPrivate::maxTimeBuffered() const\r
256 {\r
257     // rtsp streams are not buffered\r
258     return m_isStreaming ? 0 : maxTimeLoaded();\r
259 }\r
260 \r
261 float MediaPlayerPrivate::maxTimeSeekable() const\r
262 {\r
263     // infinite duration means live stream\r
264     return !isfinite(duration()) ? 0 : maxTimeLoaded();\r
265 }\r
266 \r
267 float MediaPlayerPrivate::maxTimeLoaded() const\r
268 {\r
269     if (!m_qtMovie)\r
270         return 0;\r
271     return m_qtMovie->maxTimeLoaded(); \r
272 }\r
273 \r
274 unsigned MediaPlayerPrivate::bytesLoaded() const\r
275 {\r
276     if (!m_qtMovie)\r
277         return 0;\r
278     float dur = duration();\r
279     float maxTime = maxTimeLoaded();\r
280     if (!dur)\r
281         return 0;\r
282     return totalBytes() * maxTime / dur;\r
283 }\r
284 \r
285 bool MediaPlayerPrivate::totalBytesKnown() const\r
286 {\r
287     return totalBytes() > 0;\r
288 }\r
289 \r
290 unsigned MediaPlayerPrivate::totalBytes() const\r
291 {\r
292     if (!m_qtMovie)\r
293         return 0;\r
294     return m_qtMovie->dataSize();\r
295 }\r
296 \r
297 void MediaPlayerPrivate::cancelLoad()\r
298 {\r
299     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)\r
300         return;\r
301     \r
302     // Cancel the load by destroying the movie.\r
303     m_qtMovie.clear();\r
304     \r
305     updateStates();\r
306 }\r
307 \r
308 void MediaPlayerPrivate::updateStates()\r
309 {\r
310     MediaPlayer::NetworkState oldNetworkState = m_networkState;\r
311     MediaPlayer::ReadyState oldReadyState = m_readyState;\r
312   \r
313     long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;\r
314 \r
315     if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData) {\r
316         unsigned enabledTrackCount;\r
317         m_qtMovie->disableUnsupportedTracks(enabledTrackCount);\r
318         // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>\r
319         if (!enabledTrackCount)\r
320             loadState = QTMovieLoadStateError;\r
321     }\r
322 \r
323     // "Loaded" is reserved for fully buffered movies, never the case when streaming\r
324     if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {\r
325         if (m_networkState < MediaPlayer::Loaded)\r
326             m_networkState = MediaPlayer::Loaded;\r
327         m_readyState = MediaPlayer::CanPlayThrough;\r
328     } else if (loadState >= QTMovieLoadStatePlaythroughOK) {\r
329         if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())\r
330             m_networkState = MediaPlayer::LoadedFirstFrame;\r
331         m_readyState = (m_qtMovie->rate() == 0.0f && m_startedPlaying) ? MediaPlayer::DataUnavailable : MediaPlayer::CanPlayThrough;\r
332     } else if (loadState >= QTMovieLoadStatePlayable) {\r
333         if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())\r
334             m_networkState = MediaPlayer::LoadedFirstFrame;\r
335         m_readyState = (m_qtMovie->rate() == 0.0f && m_startedPlaying) ? MediaPlayer::DataUnavailable : MediaPlayer::CanPlay;\r
336     } else if (loadState >= QTMovieLoadStateLoaded) {\r
337         if (m_networkState < MediaPlayer::LoadedMetaData)\r
338             m_networkState = MediaPlayer::LoadedMetaData;\r
339         m_readyState = MediaPlayer::DataUnavailable;\r
340     } else if (loadState > QTMovieLoadStateError) {\r
341         if (m_networkState < MediaPlayer::Loading)\r
342             m_networkState = MediaPlayer::Loading;\r
343         m_readyState = MediaPlayer::DataUnavailable;        \r
344     } else {\r
345         m_networkState = MediaPlayer::LoadFailed;\r
346         m_readyState = MediaPlayer::DataUnavailable; \r
347     }\r
348 \r
349     if (seeking())\r
350         m_readyState = MediaPlayer::DataUnavailable;\r
351     \r
352     if (m_networkState != oldNetworkState)\r
353         m_player->networkStateChanged();\r
354     if (m_readyState != oldReadyState)\r
355         m_player->readyStateChanged();\r
356 }\r
357 \r
358 \r
359 void MediaPlayerPrivate::didEnd()\r
360 {\r
361     m_endPointTimer.stop();\r
362     m_startedPlaying = false;\r
363     updateStates();\r
364     m_player->timeChanged();\r
365 }\r
366 \r
367 void MediaPlayerPrivate::setRect(const IntRect& r) \r
368\r
369     if (m_qtMovie)\r
370         m_qtMovie->setSize(r.width(), r.height());\r
371 }\r
372 \r
373 void MediaPlayerPrivate::setVisible(bool b)\r
374 {\r
375     if (!m_qtMovie)\r
376         return;\r
377     m_qtMovie->setVisible(b);\r
378 }\r
379 \r
380 void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)\r
381 {\r
382     if (p->paintingDisabled() || !m_qtMovie)\r
383         return;\r
384     HDC hdc = p->getWindowsContext(r);\r
385     m_qtMovie->paint(hdc, r.x(), r.y());\r
386     p->releaseWindowsContext(hdc, r);\r
387 }\r
388 \r
389 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)\r
390 {\r
391     unsigned count = QTMovieWin::countSupportedTypes();\r
392     for (unsigned n = 0; n < count; n++) {\r
393         const UChar* character;\r
394         unsigned len;\r
395         QTMovieWin::getSupportedType(n, character, len);\r
396         if (len)\r
397             types.add(String(character, len));\r
398     }\r
399\r
400 \r
401 bool MediaPlayerPrivate::isAvailable()\r
402 {\r
403     return QTMovieWin::initializeQuickTime();\r
404 }\r
405 \r
406 void MediaPlayerPrivate::movieEnded(QTMovieWin* movie)\r
407 {\r
408     ASSERT(m_qtMovie.get() == movie);\r
409     didEnd();\r
410 }\r
411 \r
412 void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie)\r
413 {\r
414     ASSERT(m_qtMovie.get() == movie);\r
415     updateStates();\r
416 }\r
417 \r
418 void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie)\r
419 {\r
420     ASSERT(m_qtMovie.get() == movie);\r
421     updateStates();\r
422     m_player->timeChanged();\r
423 }\r
424 \r
425 void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie)\r
426 {\r
427     ASSERT(m_qtMovie.get() == movie);\r
428     m_player->repaint();\r
429 }\r
430 \r
431 }\r
432 \r
433 #endif\r
434 \r