• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "MediaPlayerPrivateAndroid.h"
28 
29 #if ENABLE(VIDEO)
30 
31 #include "BaseLayerAndroid.h"
32 #include "DocumentLoader.h"
33 #include "Frame.h"
34 #include "FrameLoader.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "SkiaUtils.h"
38 #include "TilesManager.h"
39 #include "VideoLayerAndroid.h"
40 #include "WebCoreJni.h"
41 #include "WebViewCore.h"
42 #include <GraphicsJNI.h>
43 #include <JNIHelp.h>
44 #include <JNIUtility.h>
45 #include <SkBitmap.h>
46 #include <gui/SurfaceTexture.h>
47 
48 using namespace android;
49 // Forward decl
50 namespace android {
51 sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
52 };
53 
54 namespace WebCore {
55 
56 static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy";
57 static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio";
58 
59 struct MediaPlayerPrivate::JavaGlue {
60     jobject   m_javaProxy;
61     jmethodID m_play;
62     jmethodID m_teardown;
63     jmethodID m_seek;
64     jmethodID m_pause;
65     // Audio
66     jmethodID m_newInstance;
67     jmethodID m_setDataSource;
68     jmethodID m_getMaxTimeSeekable;
69     // Video
70     jmethodID m_getInstance;
71     jmethodID m_loadPoster;
72 };
73 
~MediaPlayerPrivate()74 MediaPlayerPrivate::~MediaPlayerPrivate()
75 {
76     TilesManager::instance()->videoLayerManager()->removeLayer(m_videoLayer->uniqueId());
77     // m_videoLayer is reference counted, unref is enough here.
78     m_videoLayer->unref();
79     if (m_glue->m_javaProxy) {
80         JNIEnv* env = JSC::Bindings::getJNIEnv();
81         if (env) {
82             env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_teardown);
83             env->DeleteGlobalRef(m_glue->m_javaProxy);
84         }
85     }
86     delete m_glue;
87 }
88 
registerMediaEngine(MediaEngineRegistrar registrar)89 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
90 {
91     registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
92 }
93 
supportsType(const String & type,const String & codecs)94 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
95 {
96     if (WebViewCore::isSupportedMediaMimeType(type))
97         return MediaPlayer::MayBeSupported;
98     return MediaPlayer::IsNotSupported;
99 }
100 
pause()101 void MediaPlayerPrivate::pause()
102 {
103     JNIEnv* env = JSC::Bindings::getJNIEnv();
104     if (!env || !m_glue->m_javaProxy || !m_url.length())
105         return;
106 
107     m_paused = true;
108     m_player->playbackStateChanged();
109     env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_pause);
110     checkException(env);
111 }
112 
setVisible(bool visible)113 void MediaPlayerPrivate::setVisible(bool visible)
114 {
115     m_isVisible = visible;
116     if (m_isVisible)
117         createJavaPlayerIfNeeded();
118 }
119 
seek(float time)120 void MediaPlayerPrivate::seek(float time)
121 {
122     JNIEnv* env = JSC::Bindings::getJNIEnv();
123     if (!env || !m_url.length())
124         return;
125 
126     if (m_glue->m_javaProxy) {
127         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast<jint>(time * 1000.0f));
128         m_currentTime = time;
129     }
130     checkException(env);
131 }
132 
prepareToPlay()133 void MediaPlayerPrivate::prepareToPlay()
134 {
135     // We are about to start playing. Since our Java VideoView cannot
136     // buffer any data, we just simply transition to the HaveEnoughData
137     // state in here. This will allow the MediaPlayer to transition to
138     // the "play" state, at which point our VideoView will start downloading
139     // the content and start the playback.
140     m_networkState = MediaPlayer::Loaded;
141     m_player->networkStateChanged();
142     m_readyState = MediaPlayer::HaveEnoughData;
143     m_player->readyStateChanged();
144 }
145 
MediaPlayerPrivate(MediaPlayer * player)146 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
147     : m_player(player),
148     m_glue(0),
149     m_duration(1), // keep this minimal to avoid initial seek problem
150     m_currentTime(0),
151     m_paused(true),
152     m_readyState(MediaPlayer::HaveNothing),
153     m_networkState(MediaPlayer::Empty),
154     m_poster(0),
155     m_naturalSize(100, 100),
156     m_naturalSizeUnknown(true),
157     m_isVisible(false),
158     m_videoLayer(new VideoLayerAndroid())
159 {
160 }
161 
onEnded()162 void MediaPlayerPrivate::onEnded()
163 {
164     m_currentTime = duration();
165     m_player->timeChanged();
166     m_paused = true;
167     m_player->playbackStateChanged();
168     m_networkState = MediaPlayer::Idle;
169 }
170 
onPaused()171 void MediaPlayerPrivate::onPaused()
172 {
173     m_paused = true;
174     m_player->playbackStateChanged();
175     m_networkState = MediaPlayer::Idle;
176     m_player->playbackStateChanged();
177 }
178 
onTimeupdate(int position)179 void MediaPlayerPrivate::onTimeupdate(int position)
180 {
181     m_currentTime = position / 1000.0f;
182     m_player->timeChanged();
183 }
184 
onStopFullscreen()185 void MediaPlayerPrivate::onStopFullscreen()
186 {
187     if (m_player && m_player->mediaPlayerClient()
188         && m_player->mediaPlayerClient()->mediaPlayerOwningDocument()) {
189         m_player->mediaPlayerClient()->mediaPlayerOwningDocument()->webkitCancelFullScreen();
190     }
191 }
192 
193 class MediaPlayerVideoPrivate : public MediaPlayerPrivate {
194 public:
load(const String & url)195     void load(const String& url)
196     {
197         m_url = url;
198         // Cheat a bit here to make sure Window.onLoad event can be triggered
199         // at the right time instead of real video play time, since only full
200         // screen video play is supported in Java's VideoView.
201         // See also comments in prepareToPlay function.
202         m_networkState = MediaPlayer::Loading;
203         m_player->networkStateChanged();
204         m_readyState = MediaPlayer::HaveCurrentData;
205         m_player->readyStateChanged();
206     }
207 
play()208     void play()
209     {
210         JNIEnv* env = JSC::Bindings::getJNIEnv();
211         if (!env || !m_url.length() || !m_glue->m_javaProxy)
212             return;
213 
214         // We only play video fullscreen on Android, so stop sites playing fullscreen video in the onload handler.
215         Frame* frame = m_player->frameView()->frame();
216         if (frame && !frame->loader()->documentLoader()->wasOnloadHandled())
217             return;
218 
219         m_paused = false;
220         m_player->playbackStateChanged();
221 
222         if (m_currentTime == duration())
223             m_currentTime = 0;
224 
225         jstring jUrl = wtfStringToJstring(env, m_url);
226         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl,
227                             static_cast<jint>(m_currentTime * 1000.0f),
228                             m_videoLayer->uniqueId());
229         env->DeleteLocalRef(jUrl);
230 
231         checkException(env);
232     }
canLoadPoster() const233     bool canLoadPoster() const { return true; }
setPoster(const String & url)234     void setPoster(const String& url)
235     {
236         if (m_posterUrl == url)
237             return;
238 
239         m_posterUrl = url;
240         JNIEnv* env = JSC::Bindings::getJNIEnv();
241         if (!env || !m_glue->m_javaProxy || !m_posterUrl.length())
242             return;
243         // Send the poster
244         jstring jUrl = wtfStringToJstring(env, m_posterUrl);
245         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
246         env->DeleteLocalRef(jUrl);
247     }
paint(GraphicsContext * ctxt,const IntRect & r)248     void paint(GraphicsContext* ctxt, const IntRect& r)
249     {
250         if (ctxt->paintingDisabled())
251             return;
252 
253         if (!m_isVisible)
254             return;
255 
256         if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
257             return;
258 
259         SkCanvas*   canvas = ctxt->platformContext()->mCanvas;
260         // We paint with the following rules in mind:
261         // - only downscale the poster, never upscale
262         // - maintain the natural aspect ratio of the poster
263         // - the poster should be centered in the target rect
264         float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
265         int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
266         int posterHeight = posterWidth / originalRatio;
267         int posterX = ((r.width() - posterWidth) / 2) + r.x();
268         int posterY = ((r.height() - posterHeight) / 2) + r.y();
269         IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
270         canvas->drawBitmapRect(*m_poster, 0, targetRect, 0);
271     }
272 
onPosterFetched(SkBitmap * poster)273     void onPosterFetched(SkBitmap* poster)
274     {
275         m_poster = poster;
276         if (m_naturalSizeUnknown) {
277             // We had to fake the size at startup, or else our paint
278             // method would not be called. If we haven't yet received
279             // the onPrepared event, update the intrinsic size to the size
280             // of the poster. That will be overriden when onPrepare comes.
281             // In case of an error, we should report the poster size, rather
282             // than our initial fake value.
283             m_naturalSize = IntSize(poster->width(), poster->height());
284             m_player->sizeChanged();
285         }
286     }
287 
onPrepared(int duration,int width,int height)288     void onPrepared(int duration, int width, int height)
289     {
290         m_duration = duration / 1000.0f;
291         m_naturalSize = IntSize(width, height);
292         m_naturalSizeUnknown = false;
293         m_player->durationChanged();
294         m_player->sizeChanged();
295         TilesManager::instance()->videoLayerManager()->updateVideoLayerSize(
296             m_player->platformLayer()->uniqueId(), width*height);
297     }
298 
hasAudio() const299     virtual bool hasAudio() const { return false; } // do not display the audio UI
hasVideo() const300     virtual bool hasVideo() const { return true; }
supportsFullscreen() const301     virtual bool supportsFullscreen() const { return true; }
302 
MediaPlayerVideoPrivate(MediaPlayer * player)303     MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player)
304     {
305         JNIEnv* env = JSC::Bindings::getJNIEnv();
306         if (!env)
307             return;
308 
309         jclass clazz = env->FindClass(g_ProxyJavaClass);
310 
311         if (!clazz)
312             return;
313 
314         m_glue = new JavaGlue;
315         m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;");
316         m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V");
317         m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;II)V");
318 
319         m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
320         m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
321         m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
322         m_glue->m_javaProxy = 0;
323         env->DeleteLocalRef(clazz);
324         // An exception is raised if any of the above fails.
325         checkException(env);
326     }
327 
createJavaPlayerIfNeeded()328     void createJavaPlayerIfNeeded()
329     {
330         // Check if we have been already created.
331         if (m_glue->m_javaProxy)
332             return;
333 
334         JNIEnv* env = JSC::Bindings::getJNIEnv();
335         if (!env)
336             return;
337 
338         jclass clazz = env->FindClass(g_ProxyJavaClass);
339 
340         if (!clazz)
341             return;
342 
343         jobject obj = 0;
344 
345         FrameView* frameView = m_player->frameView();
346         if (!frameView)
347             return;
348         AutoJObject javaObject = WebViewCore::getWebViewCore(frameView)->getJavaObject();
349         if (!javaObject.get())
350             return;
351 
352         // Get the HTML5VideoViewProxy instance
353         obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, javaObject.get(), this);
354         m_glue->m_javaProxy = env->NewGlobalRef(obj);
355         // Send the poster
356         jstring jUrl = 0;
357         if (m_posterUrl.length())
358             jUrl = wtfStringToJstring(env, m_posterUrl);
359         // Sending a NULL jUrl allows the Java side to try to load the default poster.
360         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
361         if (jUrl)
362             env->DeleteLocalRef(jUrl);
363 
364         // Clean up.
365         env->DeleteLocalRef(obj);
366         env->DeleteLocalRef(clazz);
367         checkException(env);
368     }
369 
maxTimeSeekable() const370     float maxTimeSeekable() const
371     {
372         return m_duration;
373     }
374 };
375 
376 class MediaPlayerAudioPrivate : public MediaPlayerPrivate {
377 public:
load(const String & url)378     void load(const String& url)
379     {
380         m_url = url;
381         JNIEnv* env = JSC::Bindings::getJNIEnv();
382         if (!env || !m_url.length())
383             return;
384 
385         createJavaPlayerIfNeeded();
386 
387         if (!m_glue->m_javaProxy)
388             return;
389 
390         jstring jUrl = wtfStringToJstring(env, m_url);
391         // start loading the data asynchronously
392         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_setDataSource, jUrl);
393         env->DeleteLocalRef(jUrl);
394         checkException(env);
395     }
396 
play()397     void play()
398     {
399         JNIEnv* env = JSC::Bindings::getJNIEnv();
400         if (!env || !m_url.length())
401             return;
402 
403         createJavaPlayerIfNeeded();
404 
405         if (!m_glue->m_javaProxy)
406             return;
407 
408         m_paused = false;
409         m_player->playbackStateChanged();
410         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play);
411         checkException(env);
412     }
413 
hasAudio() const414     virtual bool hasAudio() const { return true; }
hasVideo() const415     virtual bool hasVideo() const { return false; }
supportsFullscreen() const416     virtual bool supportsFullscreen() const { return false; }
417 
maxTimeSeekable() const418     float maxTimeSeekable() const
419     {
420         if (m_glue->m_javaProxy) {
421             JNIEnv* env = JSC::Bindings::getJNIEnv();
422             if (env) {
423                 float maxTime = env->CallFloatMethod(m_glue->m_javaProxy,
424                                                      m_glue->m_getMaxTimeSeekable);
425                 checkException(env);
426                 return maxTime;
427             }
428         }
429         return 0;
430     }
431 
MediaPlayerAudioPrivate(MediaPlayer * player)432     MediaPlayerAudioPrivate(MediaPlayer* player) : MediaPlayerPrivate(player)
433     {
434         JNIEnv* env = JSC::Bindings::getJNIEnv();
435         if (!env)
436             return;
437 
438         jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
439 
440         if (!clazz)
441             return;
442 
443         m_glue = new JavaGlue;
444         m_glue->m_newInstance = env->GetMethodID(clazz, "<init>", "(Landroid/webkit/WebViewCore;I)V");
445         m_glue->m_setDataSource = env->GetMethodID(clazz, "setDataSource", "(Ljava/lang/String;)V");
446         m_glue->m_play = env->GetMethodID(clazz, "play", "()V");
447         m_glue->m_getMaxTimeSeekable = env->GetMethodID(clazz, "getMaxTimeSeekable", "()F");
448         m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
449         m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
450         m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
451         m_glue->m_javaProxy = 0;
452         env->DeleteLocalRef(clazz);
453         // An exception is raised if any of the above fails.
454         checkException(env);
455     }
456 
createJavaPlayerIfNeeded()457     void createJavaPlayerIfNeeded()
458     {
459         // Check if we have been already created.
460         if (m_glue->m_javaProxy)
461             return;
462 
463         JNIEnv* env = JSC::Bindings::getJNIEnv();
464         if (!env)
465             return;
466 
467         jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
468 
469         if (!clazz)
470             return;
471 
472         FrameView* frameView = m_player->mediaPlayerClient()->mediaPlayerOwningDocument()->view();
473         if (!frameView)
474             return;
475         AutoJObject javaObject = WebViewCore::getWebViewCore(frameView)->getJavaObject();
476         if (!javaObject.get())
477             return;
478 
479         jobject obj = 0;
480 
481         // Get the HTML5Audio instance
482         obj = env->NewObject(clazz, m_glue->m_newInstance, javaObject.get(), this);
483         m_glue->m_javaProxy = env->NewGlobalRef(obj);
484 
485         // Clean up.
486         if (obj)
487             env->DeleteLocalRef(obj);
488         env->DeleteLocalRef(clazz);
489         checkException(env);
490     }
491 
onPrepared(int duration,int width,int height)492     void onPrepared(int duration, int width, int height)
493     {
494         // Android media player gives us a duration of 0 for a live
495         // stream, so in that case set the real duration to infinity.
496         // We'll still be able to handle the case that we genuinely
497         // get an audio clip with a duration of 0s as we'll get the
498         // ended event when it stops playing.
499         if (duration > 0) {
500             m_duration = duration / 1000.0f;
501         } else {
502             m_duration = std::numeric_limits<float>::infinity();
503         }
504         m_player->durationChanged();
505         m_player->sizeChanged();
506         m_player->prepareToPlay();
507     }
508 };
509 
create(MediaPlayer * player)510 MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
511 {
512     if (player->mediaElementType() == MediaPlayer::Video)
513        return new MediaPlayerVideoPrivate(player);
514     return new MediaPlayerAudioPrivate(player);
515 }
516 
517 }
518 
519 namespace android {
520 
OnPrepared(JNIEnv * env,jobject obj,int duration,int width,int height,int pointer)521 static void OnPrepared(JNIEnv* env, jobject obj, int duration, int width, int height, int pointer)
522 {
523     if (pointer) {
524         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
525         player->onPrepared(duration, width, height);
526     }
527 }
528 
OnEnded(JNIEnv * env,jobject obj,int pointer)529 static void OnEnded(JNIEnv* env, jobject obj, int pointer)
530 {
531     if (pointer) {
532         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
533         player->onEnded();
534     }
535 }
536 
OnPaused(JNIEnv * env,jobject obj,int pointer)537 static void OnPaused(JNIEnv* env, jobject obj, int pointer)
538 {
539     if (pointer) {
540         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
541         player->onPaused();
542     }
543 }
544 
OnPosterFetched(JNIEnv * env,jobject obj,jobject poster,int pointer)545 static void OnPosterFetched(JNIEnv* env, jobject obj, jobject poster, int pointer)
546 {
547     if (!pointer || !poster)
548         return;
549 
550     WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
551     SkBitmap* posterNative = GraphicsJNI::getNativeBitmap(env, poster);
552     if (!posterNative)
553         return;
554     player->onPosterFetched(posterNative);
555 }
556 
OnBuffering(JNIEnv * env,jobject obj,int percent,int pointer)557 static void OnBuffering(JNIEnv* env, jobject obj, int percent, int pointer)
558 {
559     if (pointer) {
560         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
561         // TODO: player->onBuffering(percent);
562     }
563 }
564 
OnTimeupdate(JNIEnv * env,jobject obj,int position,int pointer)565 static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer)
566 {
567     if (pointer) {
568         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
569         player->onTimeupdate(position);
570     }
571 }
572 
573 // This is called on the UI thread only.
574 // The video layers are composited on the webkit thread and then copied over
575 // to the UI thread with the same ID. For rendering, we are only using the
576 // video layers on the UI thread. Therefore, on the UI thread, we have to use
577 // the videoLayerId from Java side to find the exact video layer in the tree
578 // to set the surface texture.
579 // Every time a play call into Java side, the videoLayerId will be sent and
580 // saved in Java side. Then every time setBaseLayer call, the saved
581 // videoLayerId will be passed to this function to find the Video Layer.
582 // Return value: true when the video layer is found.
SendSurfaceTexture(JNIEnv * env,jobject obj,jobject surfTex,int baseLayer,int videoLayerId,int textureName,int playerState)583 static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex,
584                                int baseLayer, int videoLayerId,
585                                int textureName, int playerState) {
586     if (!surfTex)
587         return false;
588 
589     sp<SurfaceTexture> texture = android::SurfaceTexture_getSurfaceTexture(env, surfTex);
590     if (!texture.get())
591         return false;
592 
593     BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(baseLayer);
594     if (!layerImpl)
595         return false;
596     if (!layerImpl->countChildren())
597         return false;
598     LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(layerImpl->getChild(0));
599     if (!compositedRoot)
600         return false;
601 
602     VideoLayerAndroid* videoLayer =
603         static_cast<VideoLayerAndroid*>(compositedRoot->findById(videoLayerId));
604     if (!videoLayer)
605         return false;
606 
607     // Set the SurfaceTexture to the layer we found
608     videoLayer->setSurfaceTexture(texture, textureName, static_cast<PlayerState>(playerState));
609     return true;
610 }
611 
OnStopFullscreen(JNIEnv * env,jobject obj,int pointer)612 static void OnStopFullscreen(JNIEnv* env, jobject obj, int pointer)
613 {
614     if (pointer) {
615         WebCore::MediaPlayerPrivate* player =
616             reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
617         player->onStopFullscreen();
618     }
619 }
620 
621 /*
622  * JNI registration
623  */
624 static JNINativeMethod g_MediaPlayerMethods[] = {
625     { "nativeOnPrepared", "(IIII)V",
626         (void*) OnPrepared },
627     { "nativeOnEnded", "(I)V",
628         (void*) OnEnded },
629     { "nativeOnStopFullscreen", "(I)V",
630         (void*) OnStopFullscreen },
631     { "nativeOnPaused", "(I)V",
632         (void*) OnPaused },
633     { "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V",
634         (void*) OnPosterFetched },
635     { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z",
636         (void*) SendSurfaceTexture },
637     { "nativeOnTimeupdate", "(II)V",
638         (void*) OnTimeupdate },
639 };
640 
641 static JNINativeMethod g_MediaAudioPlayerMethods[] = {
642     { "nativeOnBuffering", "(II)V",
643         (void*) OnBuffering },
644     { "nativeOnEnded", "(I)V",
645         (void*) OnEnded },
646     { "nativeOnPrepared", "(IIII)V",
647         (void*) OnPrepared },
648     { "nativeOnTimeupdate", "(II)V",
649         (void*) OnTimeupdate },
650 };
651 
registerMediaPlayerVideo(JNIEnv * env)652 int registerMediaPlayerVideo(JNIEnv* env)
653 {
654     return jniRegisterNativeMethods(env, g_ProxyJavaClass,
655             g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods));
656 }
657 
registerMediaPlayerAudio(JNIEnv * env)658 int registerMediaPlayerAudio(JNIEnv* env)
659 {
660     return jniRegisterNativeMethods(env, g_ProxyJavaClassAudio,
661             g_MediaAudioPlayerMethods, NELEM(g_MediaAudioPlayerMethods));
662 }
663 
664 }
665 #endif // VIDEO
666