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