• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
createWebMediaPlayer(WebMediaPlayerClient * client,const WebURL & url,LocalFrame * frame)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 
webMediaPlayer() const64 WebMediaPlayer* WebMediaPlayerClientImpl::webMediaPlayer() const
65 {
66     return m_webMediaPlayer.get();
67 }
68 
69 // WebMediaPlayerClient --------------------------------------------------------
70 
~WebMediaPlayerClientImpl()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 
networkStateChanged()79 void WebMediaPlayerClientImpl::networkStateChanged()
80 {
81     m_client->mediaPlayerNetworkStateChanged();
82 }
83 
readyStateChanged()84 void WebMediaPlayerClientImpl::readyStateChanged()
85 {
86     m_client->mediaPlayerReadyStateChanged();
87 }
88 
timeChanged()89 void WebMediaPlayerClientImpl::timeChanged()
90 {
91     m_client->mediaPlayerTimeChanged();
92 }
93 
repaint()94 void WebMediaPlayerClientImpl::repaint()
95 {
96     m_client->mediaPlayerRepaint();
97 }
98 
durationChanged()99 void WebMediaPlayerClientImpl::durationChanged()
100 {
101     m_client->mediaPlayerDurationChanged();
102 }
103 
sizeChanged()104 void WebMediaPlayerClientImpl::sizeChanged()
105 {
106     m_client->mediaPlayerSizeChanged();
107 }
108 
volume() const109 double WebMediaPlayerClientImpl::volume() const
110 {
111     return mediaElement().playerVolume();
112 }
113 
playbackStateChanged()114 void WebMediaPlayerClientImpl::playbackStateChanged()
115 {
116     m_client->mediaPlayerPlaybackStateChanged();
117 }
118 
preload() const119 WebMediaPlayer::Preload WebMediaPlayerClientImpl::preload() const
120 {
121     return static_cast<WebMediaPlayer::Preload>(m_preload);
122 }
123 
keyAdded(const WebString & keySystem,const WebString & sessionId)124 void WebMediaPlayerClientImpl::keyAdded(const WebString& keySystem, const WebString& sessionId)
125 {
126     HTMLMediaElementEncryptedMedia::keyAdded(mediaElement(), keySystem, sessionId);
127 }
128 
keyError(const WebString & keySystem,const WebString & sessionId,MediaKeyErrorCode errorCode,unsigned short systemCode)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 
keyMessage(const WebString & keySystem,const WebString & sessionId,const unsigned char * message,unsigned messageLength,const WebURL & defaultURL)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 
keyNeeded(const WebString & contentType,const unsigned char * initData,unsigned initDataLength)139 void WebMediaPlayerClientImpl::keyNeeded(const WebString& contentType, const unsigned char* initData, unsigned initDataLength)
140 {
141     HTMLMediaElementEncryptedMedia::keyNeeded(mediaElement(), contentType, initData, initDataLength);
142 }
143 
setWebLayer(blink::WebLayer * layer)144 void WebMediaPlayerClientImpl::setWebLayer(blink::WebLayer* layer)
145 {
146     m_client->mediaPlayerSetWebLayer(layer);
147 }
148 
addAudioTrack(const WebString & id,AudioTrackKind kind,const WebString & label,const WebString & language,bool enabled)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 
removeAudioTrack(WebMediaPlayer::TrackId id)154 void WebMediaPlayerClientImpl::removeAudioTrack(WebMediaPlayer::TrackId id)
155 {
156     mediaElement().removeAudioTrack(id);
157 }
158 
addVideoTrack(const WebString & id,VideoTrackKind kind,const WebString & label,const WebString & language,bool selected)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 
removeVideoTrack(WebMediaPlayer::TrackId id)164 void WebMediaPlayerClientImpl::removeVideoTrack(WebMediaPlayer::TrackId id)
165 {
166     mediaElement().removeVideoTrack(id);
167 }
168 
addTextTrack(WebInbandTextTrack * textTrack)169 void WebMediaPlayerClientImpl::addTextTrack(WebInbandTextTrack* textTrack)
170 {
171     m_client->mediaPlayerDidAddTextTrack(textTrack);
172 }
173 
removeTextTrack(WebInbandTextTrack * textTrack)174 void WebMediaPlayerClientImpl::removeTextTrack(WebInbandTextTrack* textTrack)
175 {
176     m_client->mediaPlayerDidRemoveTextTrack(textTrack);
177 }
178 
mediaSourceOpened(WebMediaSource * webMediaSource)179 void WebMediaPlayerClientImpl::mediaSourceOpened(WebMediaSource* webMediaSource)
180 {
181     ASSERT(webMediaSource);
182     m_client->mediaPlayerMediaSourceOpened(webMediaSource);
183 }
184 
requestFullscreen()185 void WebMediaPlayerClientImpl::requestFullscreen()
186 {
187     m_client->mediaPlayerRequestFullscreen();
188 }
189 
requestSeek(double time)190 void WebMediaPlayerClientImpl::requestSeek(double time)
191 {
192     m_client->mediaPlayerRequestSeek(time);
193 }
194 
195 // MediaPlayer -------------------------------------------------
load(WebMediaPlayer::LoadType loadType,const WTF::String & url,WebMediaPlayer::CORSMode corsMode)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 
play()228 void WebMediaPlayerClientImpl::play()
229 {
230     if (m_webMediaPlayer)
231         m_webMediaPlayer->play();
232 }
233 
pause()234 void WebMediaPlayerClientImpl::pause()
235 {
236     if (m_webMediaPlayer)
237         m_webMediaPlayer->pause();
238 }
239 
duration() const240 double WebMediaPlayerClientImpl::duration() const
241 {
242     if (m_webMediaPlayer)
243         return m_webMediaPlayer->duration();
244     return 0.0;
245 }
246 
currentTime() const247 double WebMediaPlayerClientImpl::currentTime() const
248 {
249     if (m_webMediaPlayer)
250         return m_webMediaPlayer->currentTime();
251     return 0.0;
252 }
253 
seek(double time)254 void WebMediaPlayerClientImpl::seek(double time)
255 {
256     if (m_webMediaPlayer)
257         m_webMediaPlayer->seek(time);
258 }
259 
seeking() const260 bool WebMediaPlayerClientImpl::seeking() const
261 {
262     if (m_webMediaPlayer)
263         return m_webMediaPlayer->seeking();
264     return false;
265 }
266 
rate() const267 double WebMediaPlayerClientImpl::rate() const
268 {
269     return m_rate;
270 }
271 
setRate(double rate)272 void WebMediaPlayerClientImpl::setRate(double rate)
273 {
274     m_rate = rate;
275     if (m_webMediaPlayer)
276         m_webMediaPlayer->setRate(rate);
277 }
278 
paused() const279 bool WebMediaPlayerClientImpl::paused() const
280 {
281     if (m_webMediaPlayer)
282         return m_webMediaPlayer->paused();
283     return false;
284 }
285 
supportsSave() const286 bool WebMediaPlayerClientImpl::supportsSave() const
287 {
288     if (m_webMediaPlayer)
289         return m_webMediaPlayer->supportsSave();
290     return false;
291 }
292 
setPoster(const KURL & poster)293 void WebMediaPlayerClientImpl::setPoster(const KURL& poster)
294 {
295     if (m_webMediaPlayer)
296         m_webMediaPlayer->setPoster(WebURL(poster));
297 }
298 
networkState() const299 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 
maxTimeSeekable() const306 double WebMediaPlayerClientImpl::maxTimeSeekable() const
307 {
308     if (m_webMediaPlayer)
309         return m_webMediaPlayer->maxTimeSeekable();
310     return 0.0;
311 }
312 
buffered() const313 PassRefPtr<TimeRanges> WebMediaPlayerClientImpl::buffered() const
314 {
315     if (m_webMediaPlayer)
316         return TimeRanges::create(m_webMediaPlayer->buffered());
317     return TimeRanges::create();
318 }
319 
didLoadingProgress() const320 bool WebMediaPlayerClientImpl::didLoadingProgress() const
321 {
322     return m_webMediaPlayer && m_webMediaPlayer->didLoadingProgress();
323 }
324 
paint(GraphicsContext * context,const IntRect & rect)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 
copyVideoTextureToPlatformTexture(WebGraphicsContext3D * context,Platform3DObject texture,GLint level,GLenum type,GLenum internalFormat,bool premultiplyAlpha,bool flipY)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 
setPreload(MediaPlayer::Preload preload)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 
hasSingleSecurityOrigin() const362 bool WebMediaPlayerClientImpl::hasSingleSecurityOrigin() const
363 {
364     if (m_webMediaPlayer)
365         return m_webMediaPlayer->hasSingleSecurityOrigin();
366     return false;
367 }
368 
mediaTimeForTimeValue(double timeValue) const369 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)
audioSourceProvider()377 AudioSourceProvider* WebMediaPlayerClientImpl::audioSourceProvider()
378 {
379     return &m_audioSourceProvider;
380 }
381 #endif
382 
create(MediaPlayerClient * client)383 PassOwnPtr<MediaPlayer> WebMediaPlayerClientImpl::create(MediaPlayerClient* client)
384 {
385     return adoptPtr(new WebMediaPlayerClientImpl(client));
386 }
387 
388 #if OS(ANDROID)
paintOnAndroid(WebCore::GraphicsContext * context,const IntRect & rect,uint8_t alpha)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 
WebMediaPlayerClientImpl(MediaPlayerClient * client)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 
mediaElement() const436 WebCore::HTMLMediaElement& WebMediaPlayerClientImpl::mediaElement() const
437 {
438     return *static_cast<HTMLMediaElement*>(m_client);
439 }
440 
441 #if ENABLE(WEB_AUDIO)
wrap(WebAudioSourceProvider * provider)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 
setClient(AudioSourceProviderClient * client)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 
provideInput(AudioBus * bus,size_t framesToProcess)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 
setFormat(size_t numberOfChannels,float sampleRate)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