/* * Copyright (C) 2007, 2008, 2009 Apple, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if ENABLE(VIDEO) #include "MediaPlayerPrivateQuickTimeWin.h" #include "GraphicsContext.h" #include "KURL.h" #include "QTMovieWin.h" #include "ScrollView.h" #include "StringHash.h" #include #include #include #if DRAW_FRAME_RATE #include "Font.h" #include "FrameView.h" #include "Frame.h" #include "Document.h" #include "RenderObject.h" #include "RenderStyle.h" #include "Windows.h" #endif using namespace std; namespace WebCore { MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) { return new MediaPlayerPrivate(player); } void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) { if (isAvailable()) registrar(create, getSupportedTypes, supportsType); } MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_seekTo(-1) , m_endTime(numeric_limits::infinity()) , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) , m_enabledTrackCount(0) , m_totalTrackCount(0) , m_hasUnsupportedTracks(false) , m_startedPlaying(false) , m_isStreaming(false) #if DRAW_FRAME_RATE , m_frameCountWhilePlaying(0) , m_timeStartedPlaying(0) , m_timeStoppedPlaying(0) #endif { } MediaPlayerPrivate::~MediaPlayerPrivate() { } void MediaPlayerPrivate::load(const String& url) { if (!QTMovieWin::initializeQuickTime()) { // FIXME: is this the right error to return? m_networkState = MediaPlayer::DecodeError; m_player->networkStateChanged(); return; } if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; m_player->networkStateChanged(); } if (m_readyState != MediaPlayer::HaveNothing) { m_readyState = MediaPlayer::HaveNothing; m_player->readyStateChanged(); } cancelSeek(); m_qtMovie.set(new QTMovieWin(this)); m_qtMovie->load(url.characters(), url.length(), m_player->preservesPitch()); m_qtMovie->setVolume(m_player->volume()); m_qtMovie->setVisible(m_player->visible()); } void MediaPlayerPrivate::play() { if (!m_qtMovie) return; m_startedPlaying = true; #if DRAW_FRAME_RATE m_frameCountWhilePlaying = 0; #endif m_qtMovie->play(); } void MediaPlayerPrivate::pause() { if (!m_qtMovie) return; m_startedPlaying = false; #if DRAW_FRAME_RATE m_timeStoppedPlaying = GetTickCount(); #endif m_qtMovie->pause(); } float MediaPlayerPrivate::duration() const { if (!m_qtMovie) return 0; return m_qtMovie->duration(); } float MediaPlayerPrivate::currentTime() const { if (!m_qtMovie) return 0; return min(m_qtMovie->currentTime(), m_endTime); } void MediaPlayerPrivate::seek(float time) { cancelSeek(); if (!m_qtMovie) return; if (time > duration()) time = duration(); m_seekTo = time; if (maxTimeLoaded() >= m_seekTo) doSeek(); else m_seekTimer.start(0, 0.5f); } void MediaPlayerPrivate::doSeek() { float oldRate = m_qtMovie->rate(); if (oldRate) m_qtMovie->setRate(0); m_qtMovie->setCurrentTime(m_seekTo); float timeAfterSeek = currentTime(); // restore playback only if not at end, othewise QTMovie will loop if (oldRate && timeAfterSeek < duration() && timeAfterSeek < m_endTime) m_qtMovie->setRate(oldRate); cancelSeek(); } void MediaPlayerPrivate::cancelSeek() { m_seekTo = -1; m_seekTimer.stop(); } void MediaPlayerPrivate::seekTimerFired(Timer*) { if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) { cancelSeek(); updateStates(); m_player->timeChanged(); return; } if (maxTimeLoaded() >= m_seekTo) doSeek(); else { MediaPlayer::NetworkState state = networkState(); if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) { cancelSeek(); updateStates(); m_player->timeChanged(); } } } void MediaPlayerPrivate::setEndTime(float time) { m_endTime = time; } bool MediaPlayerPrivate::paused() const { if (!m_qtMovie) return true; return m_qtMovie->rate() == 0.0f; } bool MediaPlayerPrivate::seeking() const { if (!m_qtMovie) return false; return m_seekTo >= 0; } IntSize MediaPlayerPrivate::naturalSize() const { if (!m_qtMovie) return IntSize(); int width; int height; m_qtMovie->getNaturalSize(width, height); return IntSize(width, height); } bool MediaPlayerPrivate::hasVideo() const { if (!m_qtMovie) return false; return m_qtMovie->hasVideo(); } void MediaPlayerPrivate::setVolume(float volume) { if (!m_qtMovie) return; m_qtMovie->setVolume(volume); } void MediaPlayerPrivate::setRate(float rate) { if (!m_qtMovie) return; m_qtMovie->setRate(rate); } void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch) { if (!m_qtMovie) return; m_qtMovie->setPreservesPitch(preservesPitch); } int MediaPlayerPrivate::dataRate() const { // This is not used at the moment return 0; } float MediaPlayerPrivate::maxTimeBuffered() const { // rtsp streams are not buffered return m_isStreaming ? 0 : maxTimeLoaded(); } float MediaPlayerPrivate::maxTimeSeekable() const { // infinite duration means live stream return !isfinite(duration()) ? 0 : maxTimeLoaded(); } float MediaPlayerPrivate::maxTimeLoaded() const { if (!m_qtMovie) return 0; return m_qtMovie->maxTimeLoaded(); } unsigned MediaPlayerPrivate::bytesLoaded() const { if (!m_qtMovie) return 0; float dur = duration(); float maxTime = maxTimeLoaded(); if (!dur) return 0; return totalBytes() * maxTime / dur; } bool MediaPlayerPrivate::totalBytesKnown() const { return totalBytes() > 0; } unsigned MediaPlayerPrivate::totalBytes() const { if (!m_qtMovie) return 0; return m_qtMovie->dataSize(); } void MediaPlayerPrivate::cancelLoad() { if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) return; // Cancel the load by destroying the movie. m_qtMovie.clear(); updateStates(); } void MediaPlayerPrivate::updateStates() { MediaPlayer::NetworkState oldNetworkState = m_networkState; MediaPlayer::ReadyState oldReadyState = m_readyState; long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError; if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) { m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount); if (m_player->inMediaDocument()) { if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) { // This is a type of media that we do not handle directly with a