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.
6 #include "WebMediaPlayerClientImpl.h"
8 #include "WebDocument.h"
9 #include "WebFrameClient.h"
10 #include "WebFrameImpl.h"
11 #include "WebHelperPlugin.h"
12 #include "WebViewImpl.h"
13 #include "core/frame/Frame.h"
14 #include "core/html/HTMLMediaElement.h"
15 #include "core/html/TimeRanges.h"
16 #include "core/rendering/RenderLayerCompositor.h"
17 #include "core/rendering/RenderView.h"
18 #include "modules/mediastream/MediaStreamRegistry.h"
19 #include "platform/audio/AudioBus.h"
20 #include "platform/audio/AudioSourceProviderClient.h"
21 #include "platform/geometry/IntSize.h"
22 #include "platform/graphics/GraphicsContext.h"
23 #include "platform/graphics/GraphicsLayer.h"
24 #include "platform/graphics/gpu/Extensions3DUtil.h"
25 #include "platform/graphics/skia/GaneshUtils.h"
26 #include "public/platform/Platform.h"
27 #include "public/platform/WebAudioSourceProvider.h"
28 #include "public/platform/WebCString.h"
29 #include "public/platform/WebCanvas.h"
30 #include "public/platform/WebCompositorSupport.h"
31 #include "public/platform/WebContentDecryptionModule.h"
32 #include "public/platform/WebGraphicsContext3DProvider.h"
33 #include "public/platform/WebInbandTextTrack.h"
34 #include "public/platform/WebMediaPlayer.h"
35 #include "public/platform/WebRect.h"
36 #include "public/platform/WebString.h"
37 #include "public/platform/WebURL.h"
40 #include "GrContext.h"
43 #include "SkGrPixelRef.h"
47 #include "wtf/Assertions.h"
48 #include "wtf/text/CString.h"
50 using namespace WebCore;
54 static PassOwnPtr<WebMediaPlayer> createWebMediaPlayer(WebMediaPlayerClient* client, const WebURL& url, Frame* frame)
56 WebFrameImpl* webFrame = WebFrameImpl::fromFrame(frame);
58 if (!webFrame->client())
60 return adoptPtr(webFrame->client()->createMediaPlayer(webFrame, url, client));
63 WebMediaPlayer* WebMediaPlayerClientImpl::mediaPlayer() const
65 return m_webMediaPlayer.get();
68 // WebMediaPlayerClient --------------------------------------------------------
70 WebMediaPlayerClientImpl::~WebMediaPlayerClientImpl()
72 // Explicitly destroy the WebMediaPlayer to allow verification of tear down.
73 m_webMediaPlayer.clear();
75 // Ensure the m_webMediaPlayer destroyed any WebHelperPlugin used.
76 ASSERT(!m_helperPlugin);
79 void WebMediaPlayerClientImpl::networkStateChanged()
81 m_client->mediaPlayerNetworkStateChanged();
84 void WebMediaPlayerClientImpl::readyStateChanged()
86 m_client->mediaPlayerReadyStateChanged();
89 void WebMediaPlayerClientImpl::timeChanged()
91 m_client->mediaPlayerTimeChanged();
94 void WebMediaPlayerClientImpl::repaint()
96 m_client->mediaPlayerRepaint();
99 void WebMediaPlayerClientImpl::durationChanged()
101 m_client->mediaPlayerDurationChanged();
104 void WebMediaPlayerClientImpl::sizeChanged()
106 m_client->mediaPlayerSizeChanged();
109 void WebMediaPlayerClientImpl::setOpaque(bool opaque)
111 m_client->mediaPlayerSetOpaque(opaque);
114 double WebMediaPlayerClientImpl::volume() const
119 void WebMediaPlayerClientImpl::playbackStateChanged()
121 m_client->mediaPlayerPlaybackStateChanged();
124 WebMediaPlayer::Preload WebMediaPlayerClientImpl::preload() const
126 return static_cast<WebMediaPlayer::Preload>(m_preload);
129 void WebMediaPlayerClientImpl::keyAdded(const WebString& keySystem, const WebString& sessionId)
131 m_client->mediaPlayerKeyAdded(keySystem, sessionId);
134 void WebMediaPlayerClientImpl::keyError(const WebString& keySystem, const WebString& sessionId, MediaKeyErrorCode errorCode, unsigned short systemCode)
136 m_client->mediaPlayerKeyError(keySystem, sessionId, static_cast<MediaPlayerClient::MediaKeyErrorCode>(errorCode), systemCode);
139 void WebMediaPlayerClientImpl::keyMessage(const WebString& keySystem, const WebString& sessionId, const unsigned char* message, unsigned messageLength, const WebURL& defaultURL)
141 m_client->mediaPlayerKeyMessage(keySystem, sessionId, message, messageLength, defaultURL);
144 void WebMediaPlayerClientImpl::keyNeeded(const WebString& contentType, const unsigned char* initData, unsigned initDataLength)
146 m_client->mediaPlayerKeyNeeded(contentType, initData, initDataLength);
149 WebPlugin* WebMediaPlayerClientImpl::createHelperPlugin(const WebString& pluginType, WebFrame* frame)
151 ASSERT(!m_helperPlugin);
153 m_helperPlugin = adoptPtr(frame->view()->createHelperPlugin(pluginType, frame->document()));
157 WebPlugin* plugin = m_helperPlugin->getPlugin();
159 // There is no need to keep the helper plugin around and the caller
160 // should not be expected to call close after a failure (null pointer).
161 closeHelperPluginSoon(frame);
168 // FIXME: |frame| no longer needed.
169 void WebMediaPlayerClientImpl::closeHelperPluginSoon(WebFrame* frame)
171 ASSERT(m_helperPlugin);
172 m_helperPlugin.clear();
175 void WebMediaPlayerClientImpl::setWebLayer(blink::WebLayer* layer)
177 m_client->mediaPlayerSetWebLayer(layer);
180 void WebMediaPlayerClientImpl::addTextTrack(WebInbandTextTrack* textTrack)
182 m_client->mediaPlayerDidAddTrack(textTrack);
185 void WebMediaPlayerClientImpl::removeTextTrack(WebInbandTextTrack* textTrack)
187 m_client->mediaPlayerDidRemoveTrack(textTrack);
190 void WebMediaPlayerClientImpl::mediaSourceOpened(WebMediaSource* webMediaSource)
192 ASSERT(webMediaSource);
193 m_client->mediaPlayerMediaSourceOpened(webMediaSource);
196 void WebMediaPlayerClientImpl::requestFullscreen()
198 m_client->mediaPlayerRequestFullscreen();
201 void WebMediaPlayerClientImpl::requestSeek(double time)
203 m_client->mediaPlayerRequestSeek(time);
206 // MediaPlayer -------------------------------------------------
208 void WebMediaPlayerClientImpl::load(WebMediaPlayer::LoadType loadType, const WTF::String& url)
210 m_url = KURL(ParsedURLString, url);
211 m_loadType = loadType;
213 if (m_preload == MediaPlayer::None) {
214 #if ENABLE(WEB_AUDIO)
215 m_audioSourceProvider.wrap(0); // Clear weak reference to m_webMediaPlayer's WebAudioSourceProvider.
217 m_webMediaPlayer.clear();
218 m_delayingLoad = true;
223 void WebMediaPlayerClientImpl::loadInternal()
225 #if ENABLE(WEB_AUDIO)
226 m_audioSourceProvider.wrap(0); // Clear weak reference to m_webMediaPlayer's WebAudioSourceProvider.
229 // FIXME: Remove this cast
230 Frame* frame = static_cast<HTMLMediaElement*>(m_client)->document().frame();
232 WebURL poster = m_client->mediaPlayerPosterURL();
234 // This does not actually check whether the hardware can support accelerated
235 // compositing, but only if the flag is set. However, this is checked lazily
236 // in WebViewImpl::setIsAcceleratedCompositingActive() and will fail there
238 m_needsWebLayerForVideo = frame->contentRenderer()->compositor()->hasAcceleratedCompositing();
240 m_webMediaPlayer = createWebMediaPlayer(this, m_url, frame);
241 if (m_webMediaPlayer) {
242 #if ENABLE(WEB_AUDIO)
243 // Make sure if we create/re-create the WebMediaPlayer that we update our wrapper.
244 m_audioSourceProvider.wrap(m_webMediaPlayer->audioSourceProvider());
247 // Tell WebMediaPlayer about the poster image URL.
248 m_webMediaPlayer->setPoster(poster);
250 // Tell WebMediaPlayer about any connected CDM (may be null).
251 m_webMediaPlayer->setContentDecryptionModule(m_cdm);
253 WebMediaPlayer::CORSMode corsMode = static_cast<WebMediaPlayer::CORSMode>(m_client->mediaPlayerCORSMode());
254 m_webMediaPlayer->load(m_loadType, m_url, corsMode);
258 void WebMediaPlayerClientImpl::play()
260 if (m_webMediaPlayer)
261 m_webMediaPlayer->play();
264 void WebMediaPlayerClientImpl::pause()
266 if (m_webMediaPlayer)
267 m_webMediaPlayer->pause();
270 void WebMediaPlayerClientImpl::showFullscreenOverlay()
272 if (m_webMediaPlayer)
273 m_webMediaPlayer->enterFullscreen();
276 void WebMediaPlayerClientImpl::hideFullscreenOverlay()
278 if (m_webMediaPlayer)
279 m_webMediaPlayer->exitFullscreen();
282 bool WebMediaPlayerClientImpl::canShowFullscreenOverlay() const
284 return m_webMediaPlayer && m_webMediaPlayer->canEnterFullscreen();
287 MediaPlayer::MediaKeyException WebMediaPlayerClientImpl::generateKeyRequest(const String& keySystem, const unsigned char* initData, unsigned initDataLength)
289 if (!m_webMediaPlayer)
290 return MediaPlayer::InvalidPlayerState;
292 WebMediaPlayer::MediaKeyException result = m_webMediaPlayer->generateKeyRequest(keySystem, initData, initDataLength);
293 return static_cast<MediaPlayer::MediaKeyException>(result);
296 MediaPlayer::MediaKeyException WebMediaPlayerClientImpl::addKey(const String& keySystem, const unsigned char* key, unsigned keyLength, const unsigned char* initData, unsigned initDataLength, const String& sessionId)
298 if (!m_webMediaPlayer)
299 return MediaPlayer::InvalidPlayerState;
301 WebMediaPlayer::MediaKeyException result = m_webMediaPlayer->addKey(keySystem, key, keyLength, initData, initDataLength, sessionId);
302 return static_cast<MediaPlayer::MediaKeyException>(result);
305 MediaPlayer::MediaKeyException WebMediaPlayerClientImpl::cancelKeyRequest(const String& keySystem, const String& sessionId)
307 if (!m_webMediaPlayer)
308 return MediaPlayer::InvalidPlayerState;
310 WebMediaPlayer::MediaKeyException result = m_webMediaPlayer->cancelKeyRequest(keySystem, sessionId);
311 return static_cast<MediaPlayer::MediaKeyException>(result);
314 void WebMediaPlayerClientImpl::setContentDecryptionModule(WebContentDecryptionModule* cdm)
317 if (m_webMediaPlayer)
318 m_webMediaPlayer->setContentDecryptionModule(cdm);
321 void WebMediaPlayerClientImpl::prepareToPlay()
327 IntSize WebMediaPlayerClientImpl::naturalSize() const
329 if (m_webMediaPlayer)
330 return m_webMediaPlayer->naturalSize();
334 bool WebMediaPlayerClientImpl::hasVideo() const
336 if (m_webMediaPlayer)
337 return m_webMediaPlayer->hasVideo();
341 bool WebMediaPlayerClientImpl::hasAudio() const
343 if (m_webMediaPlayer)
344 return m_webMediaPlayer->hasAudio();
348 double WebMediaPlayerClientImpl::duration() const
350 if (m_webMediaPlayer)
351 return m_webMediaPlayer->duration();
355 double WebMediaPlayerClientImpl::currentTime() const
357 if (m_webMediaPlayer)
358 return m_webMediaPlayer->currentTime();
362 void WebMediaPlayerClientImpl::seek(double time)
364 if (m_webMediaPlayer)
365 m_webMediaPlayer->seek(time);
368 bool WebMediaPlayerClientImpl::seeking() const
370 if (m_webMediaPlayer)
371 return m_webMediaPlayer->seeking();
375 double WebMediaPlayerClientImpl::rate() const
380 void WebMediaPlayerClientImpl::setRate(double rate)
383 if (m_webMediaPlayer)
384 m_webMediaPlayer->setRate(rate);
387 bool WebMediaPlayerClientImpl::paused() const
389 if (m_webMediaPlayer)
390 return m_webMediaPlayer->paused();
394 bool WebMediaPlayerClientImpl::supportsSave() const
396 if (m_webMediaPlayer)
397 return m_webMediaPlayer->supportsSave();
401 void WebMediaPlayerClientImpl::setVolume(double volume)
404 if (m_webMediaPlayer && !m_muted)
405 m_webMediaPlayer->setVolume(volume);
408 void WebMediaPlayerClientImpl::setMuted(bool muted)
411 if (m_webMediaPlayer)
412 m_webMediaPlayer->setVolume(muted ? 0 : m_volume);
415 void WebMediaPlayerClientImpl::setPoster(const KURL& poster)
417 if (m_webMediaPlayer)
418 m_webMediaPlayer->setPoster(WebURL(poster));
421 MediaPlayer::NetworkState WebMediaPlayerClientImpl::networkState() const
423 if (m_webMediaPlayer)
424 return static_cast<MediaPlayer::NetworkState>(m_webMediaPlayer->networkState());
425 return MediaPlayer::Empty;
428 MediaPlayer::ReadyState WebMediaPlayerClientImpl::readyState() const
430 if (m_webMediaPlayer)
431 return static_cast<MediaPlayer::ReadyState>(m_webMediaPlayer->readyState());
432 return MediaPlayer::HaveNothing;
435 double WebMediaPlayerClientImpl::maxTimeSeekable() const
437 if (m_webMediaPlayer)
438 return m_webMediaPlayer->maxTimeSeekable();
442 PassRefPtr<TimeRanges> WebMediaPlayerClientImpl::buffered() const
444 if (m_webMediaPlayer)
445 return TimeRanges::create(m_webMediaPlayer->buffered());
446 return TimeRanges::create();
449 bool WebMediaPlayerClientImpl::didLoadingProgress() const
451 return m_webMediaPlayer && m_webMediaPlayer->didLoadingProgress();
454 void WebMediaPlayerClientImpl::paint(GraphicsContext* context, const IntRect& rect)
456 // Normally GraphicsContext operations do nothing when painting is disabled.
457 // Since we're accessing platformContext() directly we have to manually
459 if (m_webMediaPlayer && !context->paintingDisabled()) {
460 // On Android, video frame is emitted as GL_TEXTURE_EXTERNAL_OES texture. We use a different path to
461 // paint the video frame into the context.
463 if (m_loadType != WebMediaPlayer::LoadTypeMediaStream) {
464 OwnPtr<blink::WebGraphicsContext3DProvider> provider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
467 paintOnAndroid(context, provider->context3d(), rect, context->getNormalizedAlpha());
471 WebCanvas* canvas = context->canvas();
472 m_webMediaPlayer->paint(canvas, rect, context->getNormalizedAlpha());
476 bool WebMediaPlayerClientImpl::copyVideoTextureToPlatformTexture(WebGraphicsContext3D* context, Platform3DObject texture, GLint level, GLenum type, GLenum internalFormat, bool premultiplyAlpha, bool flipY)
478 if (!context || !m_webMediaPlayer)
480 if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, type, level) || !context->makeContextCurrent())
483 return m_webMediaPlayer->copyVideoTextureToPlatformTexture(context, texture, level, internalFormat, type, premultiplyAlpha, flipY);
486 void WebMediaPlayerClientImpl::setPreload(MediaPlayer::Preload preload)
490 if (m_webMediaPlayer)
491 m_webMediaPlayer->setPreload(static_cast<WebMediaPlayer::Preload>(preload));
493 if (m_delayingLoad && m_preload != MediaPlayer::None)
497 bool WebMediaPlayerClientImpl::hasSingleSecurityOrigin() const
499 if (m_webMediaPlayer)
500 return m_webMediaPlayer->hasSingleSecurityOrigin();
504 bool WebMediaPlayerClientImpl::didPassCORSAccessCheck() const
506 if (m_webMediaPlayer)
507 return m_webMediaPlayer->didPassCORSAccessCheck();
511 double WebMediaPlayerClientImpl::mediaTimeForTimeValue(double timeValue) const
513 if (m_webMediaPlayer)
514 return m_webMediaPlayer->mediaTimeForTimeValue(timeValue);
518 unsigned WebMediaPlayerClientImpl::decodedFrameCount() const
520 if (m_webMediaPlayer)
521 return m_webMediaPlayer->decodedFrameCount();
525 unsigned WebMediaPlayerClientImpl::droppedFrameCount() const
527 if (m_webMediaPlayer)
528 return m_webMediaPlayer->droppedFrameCount();
532 unsigned WebMediaPlayerClientImpl::corruptedFrameCount() const
534 if (m_webMediaPlayer)
535 return m_webMediaPlayer->corruptedFrameCount();
539 unsigned WebMediaPlayerClientImpl::audioDecodedByteCount() const
541 if (m_webMediaPlayer)
542 return m_webMediaPlayer->audioDecodedByteCount();
546 unsigned WebMediaPlayerClientImpl::videoDecodedByteCount() const
548 if (m_webMediaPlayer)
549 return m_webMediaPlayer->videoDecodedByteCount();
553 #if ENABLE(WEB_AUDIO)
554 AudioSourceProvider* WebMediaPlayerClientImpl::audioSourceProvider()
556 return &m_audioSourceProvider;
560 bool WebMediaPlayerClientImpl::needsWebLayerForVideo() const
562 return m_needsWebLayerForVideo;
565 PassOwnPtr<MediaPlayer> WebMediaPlayerClientImpl::create(MediaPlayerClient* client)
567 return adoptPtr(new WebMediaPlayerClientImpl(client));
571 void WebMediaPlayerClientImpl::paintOnAndroid(WebCore::GraphicsContext* context, WebGraphicsContext3D* context3D, const IntRect& rect, uint8_t alpha)
573 if (!context || !context3D || !m_webMediaPlayer || context->paintingDisabled())
576 if (!context3D->makeContextCurrent())
579 // Copy video texture into a RGBA texture based bitmap first as video texture on Android is GL_TEXTURE_EXTERNAL_OES
580 // which is not supported by Skia yet. The bitmap's size needs to be the same as the video and use naturalSize() here.
581 // Check if we could reuse existing texture based bitmap.
582 // Otherwise, release existing texture based bitmap and allocate a new one based on video size.
583 OwnPtr<blink::WebGraphicsContext3DProvider> provider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
586 if (!ensureTextureBackedSkBitmap(provider->grContext(), m_bitmap, naturalSize(), kTopLeft_GrSurfaceOrigin, kSkia8888_GrPixelConfig))
589 // Copy video texture to bitmap texture.
590 WebCanvas* canvas = context->canvas();
591 unsigned textureId = static_cast<unsigned>((m_bitmap.getTexture())->getTextureHandle());
592 if (!m_webMediaPlayer->copyVideoTextureToPlatformTexture(context3D, textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE, true, false))
595 // 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,
596 // the texture based bitmap will be readbacked to system memory then draw onto the canvas.
598 dest.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
600 paint.setAlpha(alpha);
601 // It is not necessary to pass the dest into the drawBitmap call since all the context have been set up before calling paintCurrentFrameInContext.
602 canvas->drawBitmapRect(m_bitmap, NULL, dest, &paint);
606 void WebMediaPlayerClientImpl::startDelayedLoad()
608 ASSERT(m_delayingLoad);
609 ASSERT(!m_webMediaPlayer);
611 m_delayingLoad = false;
616 WebMediaPlayerClientImpl::WebMediaPlayerClientImpl(MediaPlayerClient* client)
618 , m_delayingLoad(false)
619 , m_preload(MediaPlayer::Auto)
620 , m_needsWebLayerForVideo(false)
625 , m_loadType(WebMediaPlayer::LoadTypeURL)
630 #if ENABLE(WEB_AUDIO)
631 void WebMediaPlayerClientImpl::AudioSourceProviderImpl::wrap(WebAudioSourceProvider* provider)
633 MutexLocker locker(provideInputLock);
635 if (m_webAudioSourceProvider && provider != m_webAudioSourceProvider)
636 m_webAudioSourceProvider->setClient(0);
638 m_webAudioSourceProvider = provider;
639 if (m_webAudioSourceProvider)
640 m_webAudioSourceProvider->setClient(m_client.get());
643 void WebMediaPlayerClientImpl::AudioSourceProviderImpl::setClient(AudioSourceProviderClient* client)
645 MutexLocker locker(provideInputLock);
648 m_client = adoptPtr(new WebMediaPlayerClientImpl::AudioClientImpl(client));
652 if (m_webAudioSourceProvider)
653 m_webAudioSourceProvider->setClient(m_client.get());
656 void WebMediaPlayerClientImpl::AudioSourceProviderImpl::provideInput(AudioBus* bus, size_t framesToProcess)
662 MutexTryLocker tryLocker(provideInputLock);
663 if (!tryLocker.locked() || !m_webAudioSourceProvider || !m_client.get()) {
668 // Wrap the AudioBus channel data using WebVector.
669 size_t n = bus->numberOfChannels();
670 WebVector<float*> webAudioData(n);
671 for (size_t i = 0; i < n; ++i)
672 webAudioData[i] = bus->channel(i)->mutableData();
674 m_webAudioSourceProvider->provideInput(webAudioData, framesToProcess);
677 void WebMediaPlayerClientImpl::AudioClientImpl::setFormat(size_t numberOfChannels, float sampleRate)
680 m_client->setFormat(numberOfChannels, sampleRate);