diff options
Diffstat (limited to 'WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp')
-rw-r--r-- | WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp | 325 |
1 files changed, 273 insertions, 52 deletions
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index a5beea1..b2fe069 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple, Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,10 +35,16 @@ #include "StringHash.h" #include "TimeRanges.h" #include "Timer.h" +#include <wtf/CurrentTime.h> #include <wtf/HashSet.h> #include <wtf/MathExtras.h> #include <wtf/StdLibExtras.h> +#if USE(ACCELERATED_COMPOSITING) +#include "GraphicsLayerCACF.h" +#include "WKCACFLayer.h" +#endif + #if DRAW_FRAME_RATE #include "Font.h" #include "FrameView.h" @@ -67,7 +73,6 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_seekTo(-1) - , m_endTime(numeric_limits<float>::infinity()) , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) @@ -76,6 +81,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_hasUnsupportedTracks(false) , m_startedPlaying(false) , m_isStreaming(false) + , m_visible(false) + , m_newFrameAvailable(false) #if DRAW_FRAME_RATE , m_frameCountWhilePlaying(0) , m_timeStartedPlaying(0) @@ -86,6 +93,19 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) MediaPlayerPrivate::~MediaPlayerPrivate() { + tearDownVideoRendering(); +} + +bool MediaPlayerPrivate::supportsFullscreen() const +{ + return true; +} + +PlatformMedia MediaPlayerPrivate::platformMedia() const +{ + PlatformMedia p; + p.qtMovie = reinterpret_cast<QTMovie*>(m_qtMovie.get()); + return p; } class TaskTimer : TimerBase { @@ -178,7 +198,7 @@ void MediaPlayerPrivate::pause() return; m_startedPlaying = false; #if DRAW_FRAME_RATE - m_timeStoppedPlaying = GetTickCount(); + m_timeStoppedPlaying = WTF::currentTime(); #endif m_qtMovie->pause(); } @@ -194,7 +214,7 @@ float MediaPlayerPrivate::currentTime() const { if (!m_qtMovie) return 0; - return min(m_qtMovie->currentTime(), m_endTime); + return m_qtMovie->currentTime(); } void MediaPlayerPrivate::seek(float time) @@ -222,7 +242,7 @@ void MediaPlayerPrivate::doSeek() 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) + if (oldRate && timeAfterSeek < duration()) m_qtMovie->setRate(oldRate); cancelSeek(); } @@ -254,11 +274,6 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*) } } -void MediaPlayerPrivate::setEndTime(float time) -{ - m_endTime = time; -} - bool MediaPlayerPrivate::paused() const { if (!m_qtMovie) @@ -332,12 +347,6 @@ void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible) m_qtMovie->setClosedCaptionsVisible(visible); } -int MediaPlayerPrivate::dataRate() const -{ - // This is not used at the moment - return 0; -} - PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { RefPtr<TimeRanges> timeRanges = TimeRanges::create(); @@ -372,11 +381,6 @@ unsigned MediaPlayerPrivate::bytesLoaded() const return totalBytes() * maxTime / dur; } -bool MediaPlayerPrivate::totalBytesKnown() const -{ - return totalBytes() > 0; -} - unsigned MediaPlayerPrivate::totalBytes() const { if (!m_qtMovie) @@ -389,9 +393,11 @@ void MediaPlayerPrivate::cancelLoad() if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) return; + tearDownVideoRendering(); + // Cancel the load by destroying the movie. m_qtMovie.clear(); - + updateStates(); } @@ -454,6 +460,9 @@ void MediaPlayerPrivate::updateStates() } } + if (isReadyForRendering() && !hasSetUpVideoRendering()) + setUpVideoRendering(); + if (seeking()) m_readyState = MediaPlayer::HaveNothing; @@ -463,6 +472,11 @@ void MediaPlayerPrivate::updateStates() m_player->readyStateChanged(); } +bool MediaPlayerPrivate::isReadyForRendering() const +{ + return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible(); +} + void MediaPlayerPrivate::sawUnsupportedTracks() { m_qtMovie->setDisabled(true); @@ -477,7 +491,7 @@ void MediaPlayerPrivate::didEnd() m_startedPlaying = false; #if DRAW_FRAME_RATE - m_timeStoppedPlaying = GetTickCount(); + m_timeStoppedPlaying = WTF::currentTime(); #endif updateStates(); m_player->timeChanged(); @@ -485,20 +499,32 @@ void MediaPlayerPrivate::didEnd() void MediaPlayerPrivate::setSize(const IntSize& size) { - if (m_hasUnsupportedTracks || !m_qtMovie) + if (m_hasUnsupportedTracks || !m_qtMovie || m_size == size) return; + m_size = size; m_qtMovie->setSize(size.width(), size.height()); } -void MediaPlayerPrivate::setVisible(bool b) +void MediaPlayerPrivate::setVisible(bool visible) { - if (m_hasUnsupportedTracks || !m_qtMovie) + if (m_hasUnsupportedTracks || !m_qtMovie || m_visible == visible) return; - m_qtMovie->setVisible(b); + + m_qtMovie->setVisible(visible); + m_visible = visible; + if (m_visible) { + if (isReadyForRendering()) + setUpVideoRendering(); + } else + tearDownVideoRendering(); } void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) { +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + return; +#endif if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks) return; @@ -529,28 +555,50 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) else p->releaseWindowsContext(hdc, r); + paintCompleted(*p, r); +} + +void MediaPlayerPrivate::paintCompleted(GraphicsContext& context, const IntRect& rect) +{ + m_newFrameAvailable = false; + #if DRAW_FRAME_RATE if (m_frameCountWhilePlaying > 10) { - Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : NULL; - Document* document = frame ? frame->document() : NULL; - RenderObject* renderer = document ? document->renderer() : NULL; - RenderStyle* styleToUse = renderer ? renderer->style() : NULL; - if (styleToUse) { - double frameRate = (m_frameCountWhilePlaying - 1) / (0.001 * ( m_startedPlaying ? (GetTickCount() - m_timeStartedPlaying) : - (m_timeStoppedPlaying - m_timeStartedPlaying) )); - String text = String::format("%1.2f", frameRate); - TextRun textRun(text.characters(), text.length()); - const Color color(255, 0, 0); - p->save(); - p->translate(r.x(), r.y() + r.height()); - p->setFont(styleToUse->font()); - p->setStrokeColor(color); - p->setStrokeStyle(SolidStroke); - p->setStrokeThickness(1.0f); - p->setFillColor(color); - p->drawText(textRun, IntPoint(2, -3)); - p->restore(); - } + double interval = m_startedPlaying ? WTF::currentTime() - m_timeStartedPlaying : m_timeStoppedPlaying - m_timeStartedPlaying; + double frameRate = (m_frameCountWhilePlaying - 1) / interval; + CGContextRef cgContext = context.platformContext(); + CGRect drawRect = rect; + + char text[8]; + _snprintf(text, sizeof(text), "%1.2f", frameRate); + + static const int fontSize = 25; + static const int fontCharWidth = 12; + static const int boxHeight = 25; + static const int boxBorderWidth = 4; + drawRect.size.width = boxBorderWidth * 2 + fontCharWidth * strlen(text); + drawRect.size.height = boxHeight; + + CGContextSaveGState(cgContext); +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + CGContextScaleCTM(cgContext, 1, -1); + CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, m_qtVideoLayer ? -rect.height() : 0); +#else + CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, 0); +#endif + static const CGFloat backgroundColor[4] = { 0.98, 0.98, 0.82, 0.8 }; + CGContextSetFillColor(cgContext, backgroundColor); + CGContextFillRect(cgContext, drawRect); + + static const CGFloat textColor[4] = { 0, 0, 0, 1 }; + CGContextSetFillColor(cgContext, textColor); + CGContextSetTextMatrix(cgContext, CGAffineTransformMakeScale(1, -1)); + CGContextSelectFont(cgContext, "Helvetica", fontSize, kCGEncodingMacRoman); + + CGContextShowTextAtPoint(cgContext, drawRect.origin.x + boxBorderWidth, drawRect.origin.y + boxHeight - boxBorderWidth, text, strlen(text)); + + CGContextRestoreGState(cgContext); } #endif } @@ -630,13 +678,21 @@ void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie) #if DRAW_FRAME_RATE if (m_startedPlaying) { m_frameCountWhilePlaying++; - // to eliminate preroll costs from our calculation, - // our frame rate calculation excludes the first frame drawn after playback starts - if (1==m_frameCountWhilePlaying) - m_timeStartedPlaying = GetTickCount(); + // To eliminate preroll costs from our calculation, our frame rate calculation excludes + // the first frame drawn after playback starts. + if (m_frameCountWhilePlaying == 1) + m_timeStartedPlaying = WTF::currentTime(); } #endif - m_player->repaint(); + + m_newFrameAvailable = true; + +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + m_qtVideoLayer->platformLayer()->setNeedsDisplay(); + else +#endif + m_player->repaint(); } bool MediaPlayerPrivate::hasSingleSecurityOrigin() const @@ -646,6 +702,171 @@ bool MediaPlayerPrivate::hasSingleSecurityOrigin() const return true; } +MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::currentRenderingMode() const +{ + if (!m_qtMovie) + return MediaRenderingNone; + +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + return MediaRenderingMovieLayer; +#endif + + return MediaRenderingSoftwareRenderer; +} + +MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMode() const +{ + if (!m_player->frameView() || !m_qtMovie) + return MediaRenderingNone; + +#if USE(ACCELERATED_COMPOSITING) + if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player)) + return MediaRenderingMovieLayer; +#endif + + return MediaRenderingSoftwareRenderer; +} + +void MediaPlayerPrivate::setUpVideoRendering() +{ + MediaRenderingMode currentMode = currentRenderingMode(); + MediaRenderingMode preferredMode = preferredRenderingMode(); + +#if !USE(ACCELERATED_COMPOSITING) + ASSERT(preferredMode != MediaRenderingMovieLayer); +#endif + + if (currentMode == preferredMode && currentMode != MediaRenderingNone) + return; + + if (currentMode != MediaRenderingNone) + tearDownVideoRendering(); + + if (preferredMode == MediaRenderingMovieLayer) + createLayerForMovie(); +} + +void MediaPlayerPrivate::tearDownVideoRendering() +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + destroyLayerForMovie(); +#endif +} + +bool MediaPlayerPrivate::hasSetUpVideoRendering() const +{ +#if USE(ACCELERATED_COMPOSITING) + return m_qtVideoLayer || currentRenderingMode() != MediaRenderingMovieLayer; +#else + return true; +#endif +} + +#if USE(ACCELERATED_COMPOSITING) + +// Up-call from compositing layer drawing callback. +void MediaPlayerPrivate::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect&) +{ + if (m_hasUnsupportedTracks) + return; + + ASSERT(supportsAcceleratedRendering()); + + // No reason to replace the current layer image unless we have something new to show. + if (!m_newFrameAvailable) + return; + + static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + void* buffer; + unsigned bitsPerPixel; + unsigned rowBytes; + unsigned width; + unsigned height; + + m_qtMovie->getCurrentFrameInfo(buffer, bitsPerPixel, rowBytes, width, height); + if (!buffer) + return ; + + RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, static_cast<UInt8*>(buffer), rowBytes * height, kCFAllocatorNull)); + RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); + RetainPtr<CGImageRef> frameImage(AdoptCF, CGImageCreate(width, height, 8, bitsPerPixel, rowBytes, colorSpace, + kCGBitmapByteOrder32Little | kCGImageAlphaFirst, provider.get(), 0, false, kCGRenderingIntentDefault)); + if (!frameImage) + return; + + IntRect rect(0, 0, m_size.width(), m_size.height()); + CGContextDrawImage(context.platformContext(), rect, frameImage.get()); + paintCompleted(context, rect); +} +#endif + +void MediaPlayerPrivate::createLayerForMovie() +{ +#if USE(ACCELERATED_COMPOSITING) + ASSERT(supportsAcceleratedRendering()); + + if (!m_qtMovie || m_qtVideoLayer) + return; + + // Do nothing if the parent layer hasn't been set up yet. + GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player); + if (!videoGraphicsLayer) + return; + + // Create a GraphicsLayer that won't be inserted directly into the render tree, but will used + // as a wrapper for a WKCACFLayer which gets inserted as the content layer of the video + // renderer's GraphicsLayer. + m_qtVideoLayer.set(new GraphicsLayerCACF(this)); + if (!m_qtVideoLayer) + return; + + // Mark the layer as drawing itself, anchored in the top left, and bottom-up. + m_qtVideoLayer->setDrawsContent(true); + m_qtVideoLayer->setAnchorPoint(FloatPoint3D()); + m_qtVideoLayer->setContentsOrientation(GraphicsLayer::CompositingCoordinatesBottomUp); +#ifndef NDEBUG + m_qtVideoLayer->setName("Video layer"); +#endif + + // Hang the video layer from the render layer. + videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer->platformLayer()); +#endif +} + +void MediaPlayerPrivate::destroyLayerForMovie() +{ +#if USE(ACCELERATED_COMPOSITING) + if (!m_qtVideoLayer) + return; + m_qtVideoLayer = 0; +#endif +} + +#if USE(ACCELERATED_COMPOSITING) +bool MediaPlayerPrivate::supportsAcceleratedRendering() const +{ + return isReadyForRendering(); +} + +void MediaPlayerPrivate::acceleratedRenderingStateChanged() +{ + // Set up or change the rendering path if necessary. + setUpVideoRendering(); +} + +void MediaPlayerPrivate::notifySyncRequired(const GraphicsLayer*) +{ + GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player)); + if (videoGraphicsLayer) + videoGraphicsLayer->notifySyncRequired(); + } + + +#endif + + } #endif |