Home | History | Annotate | Download | only in web
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "web/WebMediaPlayerClientImpl.h"
      7 
      8 #include "core/frame/LocalFrame.h"
      9 #include "core/html/HTMLMediaElement.h"
     10 #include "core/html/TimeRanges.h"
     11 #include "core/rendering/RenderView.h"
     12 #include "core/rendering/compositing/RenderLayerCompositor.h"
     13 #include "modules/encryptedmedia/HTMLMediaElementEncryptedMedia.h"
     14 #include "modules/encryptedmedia/MediaKeyNeededEvent.h"
     15 #include "modules/mediastream/MediaStreamRegistry.h"
     16 #include "platform/audio/AudioBus.h"
     17 #include "platform/audio/AudioSourceProviderClient.h"
     18 #include "platform/geometry/IntSize.h"
     19 #include "platform/graphics/GraphicsContext.h"
     20 #include "platform/graphics/GraphicsLayer.h"
     21 #include "platform/graphics/gpu/Extensions3DUtil.h"
     22 #include "platform/graphics/skia/GaneshUtils.h"
     23 #include "public/platform/Platform.h"
     24 #include "public/platform/WebAudioSourceProvider.h"
     25 #include "public/platform/WebCString.h"
     26 #include "public/platform/WebCanvas.h"
     27 #include "public/platform/WebCompositorSupport.h"
     28 #include "public/platform/WebContentDecryptionModule.h"
     29 #include "public/platform/WebGraphicsContext3DProvider.h"
     30 #include "public/platform/WebInbandTextTrack.h"
     31 #include "public/platform/WebMediaPlayer.h"
     32 #include "public/platform/WebRect.h"
     33 #include "public/platform/WebString.h"
     34 #include "public/platform/WebURL.h"
     35 #include "public/web/WebDocument.h"
     36 #include "public/web/WebFrameClient.h"
     37 #include "web/WebLocalFrameImpl.h"
     38 #include "web/WebViewImpl.h"
     39 
     40 #if OS(ANDROID)
     41 #include "GrContext.h"
     42 #include "GrTypes.h"
     43 #include "SkCanvas.h"
     44 #include "SkGrPixelRef.h"
     45 #endif
     46 
     47 
     48 #include "wtf/Assertions.h"
     49 #include "wtf/text/CString.h"
     50 
     51 using namespace WebCore;
     52 
     53 namespace blink {
     54 
     55 static PassOwnPtr<WebMediaPlayer> createWebMediaPlayer(WebMediaPlayerClient* client, const WebURL& url, LocalFrame* frame)
     56 {
     57     WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame);
     58 
     59     if (!webFrame || !webFrame->client())
     60         return nullptr;
     61     return adoptPtr(webFrame->client()->createMediaPlayer(webFrame, url, client));
     62 }
     63 
     64 WebMediaPlayer* WebMediaPlayerClientImpl::webMediaPlayer() const
     65 {
     66     return m_webMediaPlayer.get();
     67 }
     68 
     69 // WebMediaPlayerClient --------------------------------------------------------
     70 
     71 WebMediaPlayerClientImpl::~WebMediaPlayerClientImpl()
     72 {
     73     // Explicitly destroy the WebMediaPlayer to allow verification of tear down.
     74     m_webMediaPlayer.clear();
     75 
     76     HTMLMediaElementEncryptedMedia::playerDestroyed(mediaElement());
     77 }
     78 
     79 void WebMediaPlayerClientImpl::networkStateChanged()
     80 {
     81     m_client->mediaPlayerNetworkStateChanged();
     82 }
     83 
     84 void WebMediaPlayerClientImpl::readyStateChanged()
     85 {
     86     m_client->mediaPlayerReadyStateChanged();
     87 }
     88 
     89 void WebMediaPlayerClientImpl::timeChanged()
     90 {
     91     m_client->mediaPlayerTimeChanged();
     92 }
     93 
     94 void WebMediaPlayerClientImpl::repaint()
     95 {
     96     m_client->mediaPlayerRepaint();
     97 }
     98 
     99 void WebMediaPlayerClientImpl::durationChanged()
    100 {
    101     m_client->mediaPlayerDurationChanged();
    102 }
    103 
    104 void WebMediaPlayerClientImpl::sizeChanged()
    105 {
    106     m_client->mediaPlayerSizeChanged();
    107 }
    108 
    109 double WebMediaPlayerClientImpl::volume() const
    110 {
    111     return mediaElement().playerVolume();
    112 }
    113 
    114 void WebMediaPlayerClientImpl::playbackStateChanged()
    115 {
    116     m_client->mediaPlayerPlaybackStateChanged();
    117 }
    118 
    119 WebMediaPlayer::Preload WebMediaPlayerClientImpl::preload() const
    120 {
    121     return static_cast<WebMediaPlayer::Preload>(m_preload);
    122 }
    123 
    124 void WebMediaPlayerClientImpl::keyAdded(const WebString& keySystem, const WebString& sessionId)
    125 {
    126     HTMLMediaElementEncryptedMedia::keyAdded(mediaElement(), keySystem, sessionId);
    127 }
    128 
    129 void WebMediaPlayerClientImpl::keyError(const WebString& keySystem, const WebString& sessionId, MediaKeyErrorCode errorCode, unsigned short systemCode)
    130 {
    131     HTMLMediaElementEncryptedMedia::keyError(mediaElement(), keySystem, sessionId, errorCode, systemCode);
    132 }
    133 
    134 void WebMediaPlayerClientImpl::keyMessage(const WebString& keySystem, const WebString& sessionId, const unsigned char* message, unsigned messageLength, const WebURL& defaultURL)
    135 {
    136     HTMLMediaElementEncryptedMedia::keyMessage(mediaElement(), keySystem, sessionId, message, messageLength, defaultURL);
    137 }
    138 
    139 void WebMediaPlayerClientImpl::keyNeeded(const WebString& contentType, const unsigned char* initData, unsigned initDataLength)
    140 {
    141     HTMLMediaElementEncryptedMedia::keyNeeded(mediaElement(), contentType, initData, initDataLength);
    142 }
    143 
    144 void WebMediaPlayerClientImpl::setWebLayer(blink::WebLayer* layer)
    145 {
    146     m_client->mediaPlayerSetWebLayer(layer);
    147 }
    148 
    149 WebMediaPlayer::TrackId WebMediaPlayerClientImpl::addAudioTrack(const WebString& id, AudioTrackKind kind, const WebString& label, const WebString& language, bool enabled)
    150 {
    151     return mediaElement().addAudioTrack(id, kind, label, language, enabled);
    152 }
    153 
    154 void WebMediaPlayerClientImpl::removeAudioTrack(WebMediaPlayer::TrackId id)
    155 {
    156     mediaElement().removeAudioTrack(id);
    157 }
    158 
    159 WebMediaPlayer::TrackId WebMediaPlayerClientImpl::addVideoTrack(const WebString& id, VideoTrackKind kind, const WebString& label, const WebString& language, bool selected)
    160 {
    161     return mediaElement().addVideoTrack(id, kind, label, language, selected);
    162 }
    163 
    164 void WebMediaPlayerClientImpl::removeVideoTrack(WebMediaPlayer::TrackId id)
    165 {
    166     mediaElement().removeVideoTrack(id);
    167 }
    168 
    169 void WebMediaPlayerClientImpl::addTextTrack(WebInbandTextTrack* textTrack)
    170 {
    171     m_client->mediaPlayerDidAddTextTrack(textTrack);
    172 }
    173 
    174 void WebMediaPlayerClientImpl::removeTextTrack(WebInbandTextTrack* textTrack)
    175 {
    176     m_client->mediaPlayerDidRemoveTextTrack(textTrack);
    177 }
    178 
    179 void WebMediaPlayerClientImpl::mediaSourceOpened(WebMediaSource* webMediaSource)
    180 {
    181     ASSERT(webMediaSource);
    182     m_client->mediaPlayerMediaSourceOpened(webMediaSource);
    183 }
    184 
    185 void WebMediaPlayerClientImpl::requestFullscreen()
    186 {
    187     m_client->mediaPlayerRequestFullscreen();
    188 }
    189 
    190 void WebMediaPlayerClientImpl::requestSeek(double time)
    191 {
    192     m_client->mediaPlayerRequestSeek(time);
    193 }
    194 
    195 // MediaPlayer -------------------------------------------------
    196 void WebMediaPlayerClientImpl::load(WebMediaPlayer::LoadType loadType, const WTF::String& url, WebMediaPlayer::CORSMode corsMode)
    197 {
    198     ASSERT(!m_webMediaPlayer);
    199 
    200     // FIXME: Remove this cast
    201     LocalFrame* frame = mediaElement().document().frame();
    202 
    203     WebURL poster = m_client->mediaPlayerPosterURL();
    204 
    205     KURL kurl(ParsedURLString, url);
    206     m_webMediaPlayer = createWebMediaPlayer(this, kurl, frame);
    207     if (!m_webMediaPlayer)
    208         return;
    209 
    210 #if ENABLE(WEB_AUDIO)
    211     // Make sure if we create/re-create the WebMediaPlayer that we update our wrapper.
    212     m_audioSourceProvider.wrap(m_webMediaPlayer->audioSourceProvider());
    213 #endif
    214 
    215     m_webMediaPlayer->setVolume(mediaElement().playerVolume());
    216 
    217     m_webMediaPlayer->setPoster(poster);
    218 
    219 #if OS(ANDROID)
    220     m_usePaintOnAndroid = (loadType != WebMediaPlayer::LoadTypeMediaStream);
    221 #endif
    222 
    223     // Tell WebMediaPlayer about any connected CDM (may be null).
    224     m_webMediaPlayer->setContentDecryptionModule(HTMLMediaElementEncryptedMedia::contentDecryptionModule(mediaElement()));
    225     m_webMediaPlayer->load(loadType, kurl, corsMode);
    226 }
    227 
    228 void WebMediaPlayerClientImpl::play()
    229 {
    230     if (m_webMediaPlayer)
    231         m_webMediaPlayer->play();
    232 }
    233 
    234 void WebMediaPlayerClientImpl::pause()
    235 {
    236     if (m_webMediaPlayer)
    237         m_webMediaPlayer->pause();
    238 }
    239 
    240 double WebMediaPlayerClientImpl::duration() const
    241 {
    242     if (m_webMediaPlayer)
    243         return m_webMediaPlayer->duration();
    244     return 0.0;
    245 }
    246 
    247 double WebMediaPlayerClientImpl::currentTime() const
    248 {
    249     if (m_webMediaPlayer)
    250         return m_webMediaPlayer->currentTime();
    251     return 0.0;
    252 }
    253 
    254 void WebMediaPlayerClientImpl::seek(double time)
    255 {
    256     if (m_webMediaPlayer)
    257         m_webMediaPlayer->seek(time);
    258 }
    259 
    260 bool WebMediaPlayerClientImpl::seeking() const
    261 {
    262     if (m_webMediaPlayer)
    263         return m_webMediaPlayer->seeking();
    264     return false;
    265 }
    266 
    267 double WebMediaPlayerClientImpl::rate() const
    268 {
    269     return m_rate;
    270 }
    271 
    272 void WebMediaPlayerClientImpl::setRate(double rate)
    273 {
    274     m_rate = rate;
    275     if (m_webMediaPlayer)
    276         m_webMediaPlayer->setRate(rate);
    277 }
    278 
    279 bool WebMediaPlayerClientImpl::paused() const
    280 {
    281     if (m_webMediaPlayer)
    282         return m_webMediaPlayer->paused();
    283     return false;
    284 }
    285 
    286 bool WebMediaPlayerClientImpl::supportsSave() const
    287 {
    288     if (m_webMediaPlayer)
    289         return m_webMediaPlayer->supportsSave();
    290     return false;
    291 }
    292 
    293 void WebMediaPlayerClientImpl::setPoster(const KURL& poster)
    294 {
    295     if (m_webMediaPlayer)
    296         m_webMediaPlayer->setPoster(WebURL(poster));
    297 }
    298 
    299 MediaPlayer::NetworkState WebMediaPlayerClientImpl::networkState() const
    300 {
    301     if (m_webMediaPlayer)
    302         return static_cast<MediaPlayer::NetworkState>(m_webMediaPlayer->networkState());
    303     return MediaPlayer::Empty;
    304 }
    305 
    306 double WebMediaPlayerClientImpl::maxTimeSeekable() const
    307 {
    308     if (m_webMediaPlayer)
    309         return m_webMediaPlayer->maxTimeSeekable();
    310     return 0.0;
    311 }
    312 
    313 PassRefPtr<TimeRanges> WebMediaPlayerClientImpl::buffered() const
    314 {
    315     if (m_webMediaPlayer)
    316         return TimeRanges::create(m_webMediaPlayer->buffered());
    317     return TimeRanges::create();
    318 }
    319 
    320 bool WebMediaPlayerClientImpl::didLoadingProgress() const
    321 {
    322     return m_webMediaPlayer && m_webMediaPlayer->didLoadingProgress();
    323 }
    324 
    325 void WebMediaPlayerClientImpl::paint(GraphicsContext* context, const IntRect& rect)
    326 {
    327     // Normally GraphicsContext operations do nothing when painting is disabled.
    328     // Since we're accessing platformContext() directly we have to manually
    329     // check.
    330     if (m_webMediaPlayer && !context->paintingDisabled()) {
    331         // On Android, video frame is emitted as GL_TEXTURE_EXTERNAL_OES texture. We use a different path to
    332         // paint the video frame into the context.
    333 #if OS(ANDROID)
    334         if (m_usePaintOnAndroid) {
    335             paintOnAndroid(context, rect, context->getNormalizedAlpha());
    336             return;
    337         }
    338 #endif
    339         WebCanvas* canvas = context->canvas();
    340         m_webMediaPlayer->paint(canvas, rect, context->getNormalizedAlpha());
    341     }
    342 }
    343 
    344 bool WebMediaPlayerClientImpl::copyVideoTextureToPlatformTexture(WebGraphicsContext3D* context, Platform3DObject texture, GLint level, GLenum type, GLenum internalFormat, bool premultiplyAlpha, bool flipY)
    345 {
    346     if (!context || !m_webMediaPlayer)
    347         return false;
    348     if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, type, level) || !context->makeContextCurrent())
    349         return false;
    350 
    351     return m_webMediaPlayer->copyVideoTextureToPlatformTexture(context, texture, level, internalFormat, type, premultiplyAlpha, flipY);
    352 }
    353 
    354 void WebMediaPlayerClientImpl::setPreload(MediaPlayer::Preload preload)
    355 {
    356     m_preload = preload;
    357 
    358     if (m_webMediaPlayer)
    359         m_webMediaPlayer->setPreload(static_cast<WebMediaPlayer::Preload>(preload));
    360 }
    361 
    362 bool WebMediaPlayerClientImpl::hasSingleSecurityOrigin() const
    363 {
    364     if (m_webMediaPlayer)
    365         return m_webMediaPlayer->hasSingleSecurityOrigin();
    366     return false;
    367 }
    368 
    369 double WebMediaPlayerClientImpl::mediaTimeForTimeValue(double timeValue) const
    370 {
    371     if (m_webMediaPlayer)
    372         return m_webMediaPlayer->mediaTimeForTimeValue(timeValue);
    373     return timeValue;
    374 }
    375 
    376 #if ENABLE(WEB_AUDIO)
    377 AudioSourceProvider* WebMediaPlayerClientImpl::audioSourceProvider()
    378 {
    379     return &m_audioSourceProvider;
    380 }
    381 #endif
    382 
    383 PassOwnPtr<MediaPlayer> WebMediaPlayerClientImpl::create(MediaPlayerClient* client)
    384 {
    385     return adoptPtr(new WebMediaPlayerClientImpl(client));
    386 }
    387 
    388 #if OS(ANDROID)
    389 void WebMediaPlayerClientImpl::paintOnAndroid(WebCore::GraphicsContext* context, const IntRect& rect, uint8_t alpha)
    390 {
    391     OwnPtr<blink::WebGraphicsContext3DProvider> provider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
    392     if (!provider)
    393         return;
    394     WebGraphicsContext3D* context3D = provider->context3d();
    395     if (!context || !context3D || !m_webMediaPlayer || context->paintingDisabled())
    396         return;
    397 
    398     if (!context3D->makeContextCurrent())
    399         return;
    400 
    401     // Copy video texture into a RGBA texture based bitmap first as video texture on Android is GL_TEXTURE_EXTERNAL_OES
    402     // which is not supported by Skia yet. The bitmap's size needs to be the same as the video and use naturalSize() here.
    403     // Check if we could reuse existing texture based bitmap.
    404     // Otherwise, release existing texture based bitmap and allocate a new one based on video size.
    405     if (!ensureTextureBackedSkBitmap(provider->grContext(), m_bitmap, m_webMediaPlayer->naturalSize(), kTopLeft_GrSurfaceOrigin, kSkia8888_GrPixelConfig))
    406         return;
    407 
    408     // Copy video texture to bitmap texture.
    409     WebCanvas* canvas = context->canvas();
    410     unsigned textureId = static_cast<unsigned>((m_bitmap.getTexture())->getTextureHandle());
    411     if (!m_webMediaPlayer->copyVideoTextureToPlatformTexture(context3D, textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE, true, false))
    412         return;
    413 
    414     // Draw the texture based bitmap onto the Canvas. If the canvas is hardware based, this will do a GPU-GPU texture copy. If the canvas is software based,
    415     // the texture based bitmap will be readbacked to system memory then draw onto the canvas.
    416     SkRect dest;
    417     dest.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
    418     SkPaint paint;
    419     paint.setAlpha(alpha);
    420     // It is not necessary to pass the dest into the drawBitmap call since all the context have been set up before calling paintCurrentFrameInContext.
    421     canvas->drawBitmapRect(m_bitmap, NULL, dest, &paint);
    422 }
    423 #endif
    424 
    425 WebMediaPlayerClientImpl::WebMediaPlayerClientImpl(MediaPlayerClient* client)
    426     : m_client(client)
    427     , m_preload(MediaPlayer::Auto)
    428     , m_rate(1.0)
    429 #if OS(ANDROID)
    430     , m_usePaintOnAndroid(false)
    431 #endif
    432 {
    433     ASSERT(m_client);
    434 }
    435 
    436 WebCore::HTMLMediaElement& WebMediaPlayerClientImpl::mediaElement() const
    437 {
    438     return *static_cast<HTMLMediaElement*>(m_client);
    439 }
    440 
    441 #if ENABLE(WEB_AUDIO)
    442 void WebMediaPlayerClientImpl::AudioSourceProviderImpl::wrap(WebAudioSourceProvider* provider)
    443 {
    444     MutexLocker locker(provideInputLock);
    445 
    446     if (m_webAudioSourceProvider && provider != m_webAudioSourceProvider)
    447         m_webAudioSourceProvider->setClient(0);
    448 
    449     m_webAudioSourceProvider = provider;
    450     if (m_webAudioSourceProvider)
    451         m_webAudioSourceProvider->setClient(m_client.get());
    452 }
    453 
    454 void WebMediaPlayerClientImpl::AudioSourceProviderImpl::setClient(AudioSourceProviderClient* client)
    455 {
    456     MutexLocker locker(provideInputLock);
    457 
    458     if (client)
    459         m_client = adoptPtr(new WebMediaPlayerClientImpl::AudioClientImpl(client));
    460     else
    461         m_client.clear();
    462 
    463     if (m_webAudioSourceProvider)
    464         m_webAudioSourceProvider->setClient(m_client.get());
    465 }
    466 
    467 void WebMediaPlayerClientImpl::AudioSourceProviderImpl::provideInput(AudioBus* bus, size_t framesToProcess)
    468 {
    469     ASSERT(bus);
    470     if (!bus)
    471         return;
    472 
    473     MutexTryLocker tryLocker(provideInputLock);
    474     if (!tryLocker.locked() || !m_webAudioSourceProvider || !m_client.get()) {
    475         bus->zero();
    476         return;
    477     }
    478 
    479     // Wrap the AudioBus channel data using WebVector.
    480     size_t n = bus->numberOfChannels();
    481     WebVector<float*> webAudioData(n);
    482     for (size_t i = 0; i < n; ++i)
    483         webAudioData[i] = bus->channel(i)->mutableData();
    484 
    485     m_webAudioSourceProvider->provideInput(webAudioData, framesToProcess);
    486 }
    487 
    488 void WebMediaPlayerClientImpl::AudioClientImpl::setFormat(size_t numberOfChannels, float sampleRate)
    489 {
    490     if (m_client)
    491         m_client->setFormat(numberOfChannels, sampleRate);
    492 }
    493 
    494 #endif
    495 
    496 } // namespace blink
    497