Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #if ENABLE(VIDEO)
     29 #include "MediaPlayerPrivateQuickTimeWin.h"
     30 
     31 #include "GraphicsContext.h"
     32 #include "KURL.h"
     33 #include "QTMovieWin.h"
     34 #include "ScrollView.h"
     35 #include "StringHash.h"
     36 #include "TimeRanges.h"
     37 #include "Timer.h"
     38 #include <wtf/CurrentTime.h>
     39 #include <wtf/HashSet.h>
     40 #include <wtf/MathExtras.h>
     41 #include <wtf/StdLibExtras.h>
     42 
     43 #if USE(ACCELERATED_COMPOSITING)
     44 #include "GraphicsLayerCACF.h"
     45 #include "WKCACFLayer.h"
     46 #endif
     47 
     48 #if DRAW_FRAME_RATE
     49 #include "Font.h"
     50 #include "FrameView.h"
     51 #include "Frame.h"
     52 #include "Document.h"
     53 #include "RenderObject.h"
     54 #include "RenderStyle.h"
     55 #include "Windows.h"
     56 #endif
     57 
     58 using namespace std;
     59 
     60 namespace WebCore {
     61 
     62 MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
     63 {
     64     return new MediaPlayerPrivate(player);
     65 }
     66 
     67 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
     68 {
     69     if (isAvailable())
     70         registrar(create, getSupportedTypes, supportsType);
     71 }
     72 
     73 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
     74     : m_player(player)
     75     , m_seekTo(-1)
     76     , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
     77     , m_networkState(MediaPlayer::Empty)
     78     , m_readyState(MediaPlayer::HaveNothing)
     79     , m_enabledTrackCount(0)
     80     , m_totalTrackCount(0)
     81     , m_hasUnsupportedTracks(false)
     82     , m_startedPlaying(false)
     83     , m_isStreaming(false)
     84     , m_visible(false)
     85     , m_newFrameAvailable(false)
     86 #if DRAW_FRAME_RATE
     87     , m_frameCountWhilePlaying(0)
     88     , m_timeStartedPlaying(0)
     89     , m_timeStoppedPlaying(0)
     90 #endif
     91 {
     92 }
     93 
     94 MediaPlayerPrivate::~MediaPlayerPrivate()
     95 {
     96     tearDownVideoRendering();
     97 }
     98 
     99 bool MediaPlayerPrivate::supportsFullscreen() const
    100 {
    101     return true;
    102 }
    103 
    104 PlatformMedia MediaPlayerPrivate::platformMedia() const
    105 {
    106     PlatformMedia p;
    107     p.qtMovie = reinterpret_cast<QTMovie*>(m_qtMovie.get());
    108     return p;
    109 }
    110 
    111 class TaskTimer : TimerBase {
    112 public:
    113     static void initialize();
    114 
    115 private:
    116     static void setTaskTimerDelay(double);
    117     static void stopTaskTimer();
    118 
    119     void fired();
    120 
    121     static TaskTimer* s_timer;
    122 };
    123 
    124 TaskTimer* TaskTimer::s_timer = 0;
    125 
    126 void TaskTimer::initialize()
    127 {
    128     if (s_timer)
    129         return;
    130 
    131     s_timer = new TaskTimer;
    132 
    133     QTMovieWin::setTaskTimerFuncs(setTaskTimerDelay, stopTaskTimer);
    134 }
    135 
    136 void TaskTimer::setTaskTimerDelay(double delayInSeconds)
    137 {
    138     ASSERT(s_timer);
    139 
    140     s_timer->startOneShot(delayInSeconds);
    141 }
    142 
    143 void TaskTimer::stopTaskTimer()
    144 {
    145     ASSERT(s_timer);
    146 
    147     s_timer->stop();
    148 }
    149 
    150 void TaskTimer::fired()
    151 {
    152     QTMovieWin::taskTimerFired();
    153 }
    154 
    155 void MediaPlayerPrivate::load(const String& url)
    156 {
    157     if (!QTMovieWin::initializeQuickTime()) {
    158         // FIXME: is this the right error to return?
    159         m_networkState = MediaPlayer::DecodeError;
    160         m_player->networkStateChanged();
    161         return;
    162     }
    163 
    164     // Initialize the task timer.
    165     TaskTimer::initialize();
    166 
    167     if (m_networkState != MediaPlayer::Loading) {
    168         m_networkState = MediaPlayer::Loading;
    169         m_player->networkStateChanged();
    170     }
    171     if (m_readyState != MediaPlayer::HaveNothing) {
    172         m_readyState = MediaPlayer::HaveNothing;
    173         m_player->readyStateChanged();
    174     }
    175     cancelSeek();
    176 
    177     m_qtMovie.set(new QTMovieWin(this));
    178     m_qtMovie->load(url.characters(), url.length(), m_player->preservesPitch());
    179     m_qtMovie->setVolume(m_player->volume());
    180     m_qtMovie->setVisible(m_player->visible());
    181 }
    182 
    183 void MediaPlayerPrivate::play()
    184 {
    185     if (!m_qtMovie)
    186         return;
    187     m_startedPlaying = true;
    188 #if DRAW_FRAME_RATE
    189     m_frameCountWhilePlaying = 0;
    190 #endif
    191 
    192     m_qtMovie->play();
    193 }
    194 
    195 void MediaPlayerPrivate::pause()
    196 {
    197     if (!m_qtMovie)
    198         return;
    199     m_startedPlaying = false;
    200 #if DRAW_FRAME_RATE
    201     m_timeStoppedPlaying = WTF::currentTime();
    202 #endif
    203     m_qtMovie->pause();
    204 }
    205 
    206 float MediaPlayerPrivate::duration() const
    207 {
    208     if (!m_qtMovie)
    209         return 0;
    210     return m_qtMovie->duration();
    211 }
    212 
    213 float MediaPlayerPrivate::currentTime() const
    214 {
    215     if (!m_qtMovie)
    216         return 0;
    217     return m_qtMovie->currentTime();
    218 }
    219 
    220 void MediaPlayerPrivate::seek(float time)
    221 {
    222     cancelSeek();
    223 
    224     if (!m_qtMovie)
    225         return;
    226 
    227     if (time > duration())
    228         time = duration();
    229 
    230     m_seekTo = time;
    231     if (maxTimeLoaded() >= m_seekTo)
    232         doSeek();
    233     else
    234         m_seekTimer.start(0, 0.5f);
    235 }
    236 
    237 void MediaPlayerPrivate::doSeek()
    238 {
    239     float oldRate = m_qtMovie->rate();
    240     if (oldRate)
    241         m_qtMovie->setRate(0);
    242     m_qtMovie->setCurrentTime(m_seekTo);
    243     float timeAfterSeek = currentTime();
    244     // restore playback only if not at end, othewise QTMovie will loop
    245     if (oldRate && timeAfterSeek < duration())
    246         m_qtMovie->setRate(oldRate);
    247     cancelSeek();
    248 }
    249 
    250 void MediaPlayerPrivate::cancelSeek()
    251 {
    252     m_seekTo = -1;
    253     m_seekTimer.stop();
    254 }
    255 
    256 void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
    257 {
    258     if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {
    259         cancelSeek();
    260         updateStates();
    261         m_player->timeChanged();
    262         return;
    263     }
    264 
    265     if (maxTimeLoaded() >= m_seekTo)
    266         doSeek();
    267     else {
    268         MediaPlayer::NetworkState state = networkState();
    269         if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
    270             cancelSeek();
    271             updateStates();
    272             m_player->timeChanged();
    273         }
    274     }
    275 }
    276 
    277 bool MediaPlayerPrivate::paused() const
    278 {
    279     if (!m_qtMovie)
    280         return true;
    281     return m_qtMovie->rate() == 0.0f;
    282 }
    283 
    284 bool MediaPlayerPrivate::seeking() const
    285 {
    286     if (!m_qtMovie)
    287         return false;
    288     return m_seekTo >= 0;
    289 }
    290 
    291 IntSize MediaPlayerPrivate::naturalSize() const
    292 {
    293     if (!m_qtMovie)
    294         return IntSize();
    295     int width;
    296     int height;
    297     m_qtMovie->getNaturalSize(width, height);
    298     return IntSize(width, height);
    299 }
    300 
    301 bool MediaPlayerPrivate::hasVideo() const
    302 {
    303     if (!m_qtMovie)
    304         return false;
    305     return m_qtMovie->hasVideo();
    306 }
    307 
    308 bool MediaPlayerPrivate::hasAudio() const
    309 {
    310     if (!m_qtMovie)
    311         return false;
    312     return m_qtMovie->hasAudio();
    313 }
    314 
    315 void MediaPlayerPrivate::setVolume(float volume)
    316 {
    317     if (!m_qtMovie)
    318         return;
    319     m_qtMovie->setVolume(volume);
    320 }
    321 
    322 void MediaPlayerPrivate::setRate(float rate)
    323 {
    324     if (!m_qtMovie)
    325         return;
    326     m_qtMovie->setRate(rate);
    327 }
    328 
    329 void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch)
    330 {
    331     if (!m_qtMovie)
    332         return;
    333     m_qtMovie->setPreservesPitch(preservesPitch);
    334 }
    335 
    336 bool MediaPlayerPrivate::hasClosedCaptions() const
    337 {
    338     if (!m_qtMovie)
    339         return false;
    340     return m_qtMovie->hasClosedCaptions();
    341 }
    342 
    343 void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible)
    344 {
    345     if (!m_qtMovie)
    346         return;
    347     m_qtMovie->setClosedCaptionsVisible(visible);
    348 }
    349 
    350 PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
    351 {
    352     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
    353     float loaded = maxTimeLoaded();
    354     // rtsp streams are not buffered
    355     if (!m_isStreaming && loaded > 0)
    356         timeRanges->add(0, loaded);
    357     return timeRanges.release();
    358 }
    359 
    360 float MediaPlayerPrivate::maxTimeSeekable() const
    361 {
    362     // infinite duration means live stream
    363     return !isfinite(duration()) ? 0 : maxTimeLoaded();
    364 }
    365 
    366 float MediaPlayerPrivate::maxTimeLoaded() const
    367 {
    368     if (!m_qtMovie)
    369         return 0;
    370     return m_qtMovie->maxTimeLoaded();
    371 }
    372 
    373 unsigned MediaPlayerPrivate::bytesLoaded() const
    374 {
    375     if (!m_qtMovie)
    376         return 0;
    377     float dur = duration();
    378     float maxTime = maxTimeLoaded();
    379     if (!dur)
    380         return 0;
    381     return totalBytes() * maxTime / dur;
    382 }
    383 
    384 unsigned MediaPlayerPrivate::totalBytes() const
    385 {
    386     if (!m_qtMovie)
    387         return 0;
    388     return m_qtMovie->dataSize();
    389 }
    390 
    391 void MediaPlayerPrivate::cancelLoad()
    392 {
    393     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
    394         return;
    395 
    396     tearDownVideoRendering();
    397 
    398     // Cancel the load by destroying the movie.
    399     m_qtMovie.clear();
    400 
    401     updateStates();
    402 }
    403 
    404 void MediaPlayerPrivate::updateStates()
    405 {
    406     MediaPlayer::NetworkState oldNetworkState = m_networkState;
    407     MediaPlayer::ReadyState oldReadyState = m_readyState;
    408 
    409     long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
    410 
    411     if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) {
    412         m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount);
    413         if (m_player->inMediaDocument()) {
    414             if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) {
    415                 // This is a type of media that we do not handle directly with a <video>
    416                 // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the
    417                 // MediaPlayerClient that we won't support it.
    418                 sawUnsupportedTracks();
    419                 return;
    420             }
    421         } else if (!m_enabledTrackCount)
    422             loadState = QTMovieLoadStateError;
    423     }
    424 
    425     // "Loaded" is reserved for fully buffered movies, never the case when streaming
    426     if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
    427         m_networkState = MediaPlayer::Loaded;
    428         m_readyState = MediaPlayer::HaveEnoughData;
    429     } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
    430         m_readyState = MediaPlayer::HaveEnoughData;
    431     } else if (loadState >= QTMovieLoadStatePlayable) {
    432         // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
    433         m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
    434     } else if (loadState >= QTMovieLoadStateLoaded) {
    435         m_readyState = MediaPlayer::HaveMetadata;
    436     } else if (loadState > QTMovieLoadStateError) {
    437         m_networkState = MediaPlayer::Loading;
    438         m_readyState = MediaPlayer::HaveNothing;
    439     } else {
    440         if (m_player->inMediaDocument()) {
    441             // Something went wrong in the loading of media within a standalone file.
    442             // This can occur with chained ref movies that eventually resolve to a
    443             // file we don't support.
    444             sawUnsupportedTracks();
    445             return;
    446         }
    447 
    448         float loaded = maxTimeLoaded();
    449         if (!loaded)
    450             m_readyState = MediaPlayer::HaveNothing;
    451 
    452         if (!m_enabledTrackCount)
    453             m_networkState = MediaPlayer::FormatError;
    454         else {
    455             // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
    456             if (loaded > 0)
    457                 m_networkState = MediaPlayer::DecodeError;
    458             else
    459                 m_readyState = MediaPlayer::HaveNothing;
    460         }
    461     }
    462 
    463     if (isReadyForRendering() && !hasSetUpVideoRendering())
    464         setUpVideoRendering();
    465 
    466     if (seeking())
    467         m_readyState = MediaPlayer::HaveNothing;
    468 
    469     if (m_networkState != oldNetworkState)
    470         m_player->networkStateChanged();
    471     if (m_readyState != oldReadyState)
    472         m_player->readyStateChanged();
    473 }
    474 
    475 bool MediaPlayerPrivate::isReadyForRendering() const
    476 {
    477     return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
    478 }
    479 
    480 void MediaPlayerPrivate::sawUnsupportedTracks()
    481 {
    482     m_qtMovie->setDisabled(true);
    483     m_hasUnsupportedTracks = true;
    484     m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
    485 }
    486 
    487 void MediaPlayerPrivate::didEnd()
    488 {
    489     if (m_hasUnsupportedTracks)
    490         return;
    491 
    492     m_startedPlaying = false;
    493 #if DRAW_FRAME_RATE
    494     m_timeStoppedPlaying = WTF::currentTime();
    495 #endif
    496     updateStates();
    497     m_player->timeChanged();
    498 }
    499 
    500 void MediaPlayerPrivate::setSize(const IntSize& size)
    501 {
    502     if (m_hasUnsupportedTracks || !m_qtMovie || m_size == size)
    503         return;
    504     m_size = size;
    505     m_qtMovie->setSize(size.width(), size.height());
    506 }
    507 
    508 void MediaPlayerPrivate::setVisible(bool visible)
    509 {
    510     if (m_hasUnsupportedTracks || !m_qtMovie || m_visible == visible)
    511         return;
    512 
    513     m_qtMovie->setVisible(visible);
    514     m_visible = visible;
    515     if (m_visible) {
    516         if (isReadyForRendering())
    517             setUpVideoRendering();
    518     } else
    519         tearDownVideoRendering();
    520 }
    521 
    522 void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
    523 {
    524 #if USE(ACCELERATED_COMPOSITING)
    525     if (m_qtVideoLayer)
    526         return;
    527 #endif
    528     if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks)
    529         return;
    530 
    531     bool usingTempBitmap = false;
    532     OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
    533     HDC hdc = p->getWindowsContext(r);
    534     if (!hdc) {
    535         // The graphics context doesn't have an associated HDC so create a temporary
    536         // bitmap where QTMovieWin can draw the frame and we can copy it.
    537         usingTempBitmap = true;
    538         bitmap.set(p->createWindowsBitmap(r.size()));
    539         hdc = bitmap->hdc();
    540 
    541         // FIXME: is this necessary??
    542         XFORM xform;
    543         xform.eM11 = 1.0f;
    544         xform.eM12 = 0.0f;
    545         xform.eM21 = 0.0f;
    546         xform.eM22 = 1.0f;
    547         xform.eDx = -r.x();
    548         xform.eDy = -r.y();
    549         SetWorldTransform(hdc, &xform);
    550     }
    551 
    552     m_qtMovie->paint(hdc, r.x(), r.y());
    553     if (usingTempBitmap)
    554         p->drawWindowsBitmap(bitmap.get(), r.topLeft());
    555     else
    556         p->releaseWindowsContext(hdc, r);
    557 
    558     paintCompleted(*p, r);
    559 }
    560 
    561 void MediaPlayerPrivate::paintCompleted(GraphicsContext& context, const IntRect& rect)
    562 {
    563     m_newFrameAvailable = false;
    564 
    565 #if DRAW_FRAME_RATE
    566     if (m_frameCountWhilePlaying > 10) {
    567         double interval =  m_startedPlaying ? WTF::currentTime() - m_timeStartedPlaying : m_timeStoppedPlaying - m_timeStartedPlaying;
    568         double frameRate = (m_frameCountWhilePlaying - 1) / interval;
    569         CGContextRef cgContext = context.platformContext();
    570         CGRect drawRect = rect;
    571 
    572         char text[8];
    573         _snprintf(text, sizeof(text), "%1.2f", frameRate);
    574 
    575         static const int fontSize = 25;
    576         static const int fontCharWidth = 12;
    577         static const int boxHeight = 25;
    578         static const int boxBorderWidth = 4;
    579         drawRect.size.width = boxBorderWidth * 2 + fontCharWidth * strlen(text);
    580         drawRect.size.height = boxHeight;
    581 
    582         CGContextSaveGState(cgContext);
    583 #if USE(ACCELERATED_COMPOSITING)
    584         if (m_qtVideoLayer)
    585             CGContextScaleCTM(cgContext, 1, -1);
    586         CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, m_qtVideoLayer ? -rect.height() : 0);
    587 #else
    588         CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, 0);
    589 #endif
    590         static const CGFloat backgroundColor[4] = { 0.98, 0.98, 0.82, 0.8 };
    591         CGContextSetFillColor(cgContext, backgroundColor);
    592         CGContextFillRect(cgContext, drawRect);
    593 
    594         static const CGFloat textColor[4] = { 0, 0, 0, 1 };
    595         CGContextSetFillColor(cgContext, textColor);
    596         CGContextSetTextMatrix(cgContext, CGAffineTransformMakeScale(1, -1));
    597         CGContextSelectFont(cgContext, "Helvetica", fontSize, kCGEncodingMacRoman);
    598 
    599         CGContextShowTextAtPoint(cgContext, drawRect.origin.x + boxBorderWidth, drawRect.origin.y + boxHeight - boxBorderWidth, text, strlen(text));
    600 
    601         CGContextRestoreGState(cgContext);
    602     }
    603 #endif
    604 }
    605 
    606 static HashSet<String> mimeTypeCache()
    607 {
    608     DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
    609     static bool typeListInitialized = false;
    610 
    611     if (!typeListInitialized) {
    612         unsigned count = QTMovieWin::countSupportedTypes();
    613         for (unsigned n = 0; n < count; n++) {
    614             const UChar* character;
    615             unsigned len;
    616             QTMovieWin::getSupportedType(n, character, len);
    617             if (len)
    618                 typeCache.add(String(character, len));
    619         }
    620 
    621         typeListInitialized = true;
    622     }
    623 
    624     return typeCache;
    625 }
    626 
    627 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
    628 {
    629     types = mimeTypeCache();
    630 }
    631 
    632 bool MediaPlayerPrivate::isAvailable()
    633 {
    634     return QTMovieWin::initializeQuickTime();
    635 }
    636 
    637 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
    638 {
    639     // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
    640     //  extended MIME type
    641     return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
    642 }
    643 
    644 void MediaPlayerPrivate::movieEnded(QTMovieWin* movie)
    645 {
    646     if (m_hasUnsupportedTracks)
    647         return;
    648 
    649     ASSERT(m_qtMovie.get() == movie);
    650     didEnd();
    651 }
    652 
    653 void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie)
    654 {
    655     if (m_hasUnsupportedTracks)
    656         return;
    657 
    658     ASSERT(m_qtMovie.get() == movie);
    659     updateStates();
    660 }
    661 
    662 void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie)
    663 {
    664     if (m_hasUnsupportedTracks)
    665         return;
    666 
    667     ASSERT(m_qtMovie.get() == movie);
    668     updateStates();
    669     m_player->timeChanged();
    670 }
    671 
    672 void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie)
    673 {
    674     if (m_hasUnsupportedTracks)
    675         return;
    676 
    677     ASSERT(m_qtMovie.get() == movie);
    678 #if DRAW_FRAME_RATE
    679     if (m_startedPlaying) {
    680         m_frameCountWhilePlaying++;
    681         // To eliminate preroll costs from our calculation, our frame rate calculation excludes
    682         // the first frame drawn after playback starts.
    683         if (m_frameCountWhilePlaying == 1)
    684             m_timeStartedPlaying = WTF::currentTime();
    685     }
    686 #endif
    687 
    688     m_newFrameAvailable = true;
    689 
    690 #if USE(ACCELERATED_COMPOSITING)
    691     if (m_qtVideoLayer)
    692         m_qtVideoLayer->platformLayer()->setNeedsDisplay();
    693     else
    694 #endif
    695         m_player->repaint();
    696 }
    697 
    698 bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
    699 {
    700     // We tell quicktime to disallow resources that come from different origins
    701     // so we all media is single origin.
    702     return true;
    703 }
    704 
    705 MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::currentRenderingMode() const
    706 {
    707     if (!m_qtMovie)
    708         return MediaRenderingNone;
    709 
    710 #if USE(ACCELERATED_COMPOSITING)
    711     if (m_qtVideoLayer)
    712         return MediaRenderingMovieLayer;
    713 #endif
    714 
    715     return MediaRenderingSoftwareRenderer;
    716 }
    717 
    718 MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMode() const
    719 {
    720     if (!m_player->frameView() || !m_qtMovie)
    721         return MediaRenderingNone;
    722 
    723 #if USE(ACCELERATED_COMPOSITING)
    724     if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
    725         return MediaRenderingMovieLayer;
    726 #endif
    727 
    728     return MediaRenderingSoftwareRenderer;
    729 }
    730 
    731 void MediaPlayerPrivate::setUpVideoRendering()
    732 {
    733     MediaRenderingMode currentMode = currentRenderingMode();
    734     MediaRenderingMode preferredMode = preferredRenderingMode();
    735 
    736 #if !USE(ACCELERATED_COMPOSITING)
    737     ASSERT(preferredMode != MediaRenderingMovieLayer);
    738 #endif
    739 
    740     if (currentMode == preferredMode && currentMode != MediaRenderingNone)
    741         return;
    742 
    743     if (currentMode != MediaRenderingNone)
    744         tearDownVideoRendering();
    745 
    746     if (preferredMode == MediaRenderingMovieLayer)
    747         createLayerForMovie();
    748 }
    749 
    750 void MediaPlayerPrivate::tearDownVideoRendering()
    751 {
    752 #if USE(ACCELERATED_COMPOSITING)
    753     if (m_qtVideoLayer)
    754         destroyLayerForMovie();
    755 #endif
    756 }
    757 
    758 bool MediaPlayerPrivate::hasSetUpVideoRendering() const
    759 {
    760 #if USE(ACCELERATED_COMPOSITING)
    761     return m_qtVideoLayer || currentRenderingMode() != MediaRenderingMovieLayer;
    762 #else
    763     return true;
    764 #endif
    765 }
    766 
    767 #if USE(ACCELERATED_COMPOSITING)
    768 
    769 // Up-call from compositing layer drawing callback.
    770 void MediaPlayerPrivate::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect&)
    771 {
    772      if (m_hasUnsupportedTracks)
    773          return;
    774 
    775     ASSERT(supportsAcceleratedRendering());
    776 
    777     // No reason to replace the current layer image unless we have something new to show.
    778     if (!m_newFrameAvailable)
    779         return;
    780 
    781     static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    782     void* buffer;
    783     unsigned bitsPerPixel;
    784     unsigned rowBytes;
    785     unsigned width;
    786     unsigned height;
    787 
    788     m_qtMovie->getCurrentFrameInfo(buffer, bitsPerPixel, rowBytes, width, height);
    789     if (!buffer)
    790         return ;
    791 
    792     RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, static_cast<UInt8*>(buffer), rowBytes * height, kCFAllocatorNull));
    793     RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData(data.get()));
    794     RetainPtr<CGImageRef> frameImage(AdoptCF, CGImageCreate(width, height, 8, bitsPerPixel, rowBytes, colorSpace,
    795         kCGBitmapByteOrder32Little | kCGImageAlphaFirst, provider.get(), 0, false, kCGRenderingIntentDefault));
    796     if (!frameImage)
    797         return;
    798 
    799     IntRect rect(0, 0, m_size.width(), m_size.height());
    800     CGContextDrawImage(context.platformContext(), rect, frameImage.get());
    801     paintCompleted(context, rect);
    802 }
    803 #endif
    804 
    805 void MediaPlayerPrivate::createLayerForMovie()
    806 {
    807 #if USE(ACCELERATED_COMPOSITING)
    808     ASSERT(supportsAcceleratedRendering());
    809 
    810     if (!m_qtMovie || m_qtVideoLayer)
    811         return;
    812 
    813     // Do nothing if the parent layer hasn't been set up yet.
    814     GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
    815     if (!videoGraphicsLayer)
    816         return;
    817 
    818     // Create a GraphicsLayer that won't be inserted directly into the render tree, but will used
    819     // as a wrapper for a WKCACFLayer which gets inserted as the content layer of the video
    820     // renderer's GraphicsLayer.
    821     m_qtVideoLayer.set(new GraphicsLayerCACF(this));
    822     if (!m_qtVideoLayer)
    823         return;
    824 
    825     // Mark the layer as drawing itself, anchored in the top left, and bottom-up.
    826     m_qtVideoLayer->setDrawsContent(true);
    827     m_qtVideoLayer->setAnchorPoint(FloatPoint3D());
    828     m_qtVideoLayer->setContentsOrientation(GraphicsLayer::CompositingCoordinatesBottomUp);
    829 #ifndef NDEBUG
    830     m_qtVideoLayer->setName("Video layer");
    831 #endif
    832 
    833     // Hang the video layer from the render layer.
    834     videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer->platformLayer());
    835 #endif
    836 }
    837 
    838 void MediaPlayerPrivate::destroyLayerForMovie()
    839 {
    840 #if USE(ACCELERATED_COMPOSITING)
    841     if (!m_qtVideoLayer)
    842         return;
    843     m_qtVideoLayer = 0;
    844 #endif
    845 }
    846 
    847 #if USE(ACCELERATED_COMPOSITING)
    848 bool MediaPlayerPrivate::supportsAcceleratedRendering() const
    849 {
    850     return isReadyForRendering();
    851 }
    852 
    853 void MediaPlayerPrivate::acceleratedRenderingStateChanged()
    854 {
    855     // Set up or change the rendering path if necessary.
    856     setUpVideoRendering();
    857 }
    858 
    859 void MediaPlayerPrivate::notifySyncRequired(const GraphicsLayer*)
    860 {
    861     GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player));
    862     if (videoGraphicsLayer)
    863         videoGraphicsLayer->notifySyncRequired();
    864  }
    865 
    866 
    867 #endif
    868 
    869 
    870 }
    871 
    872 #endif
    873