Home | History | Annotate | Download | only in WebCoreSupport
      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 
     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 
     89 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
     90 {
     91     registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
     92 }
     93 
     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 
    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 
    113 void MediaPlayerPrivate::setVisible(bool visible)
    114 {
    115     m_isVisible = visible;
    116     if (m_isVisible)
    117         createJavaPlayerIfNeeded();
    118 }
    119 
    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 
    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 
    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 
    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 
    171 void MediaPlayerPrivate::onPaused()
    172 {
    173     m_paused = true;
    174     m_player->playbackStateChanged();
    175     m_networkState = MediaPlayer::Idle;
    176     m_player->playbackStateChanged();
    177 }
    178 
    179 void MediaPlayerPrivate::onTimeupdate(int position)
    180 {
    181     m_currentTime = position / 1000.0f;
    182     m_player->timeChanged();
    183 }
    184 
    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:
    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 
    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     }
    233     bool canLoadPoster() const { return true; }
    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     }
    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 
    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 
    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 
    299     virtual bool hasAudio() const { return false; } // do not display the audio UI
    300     virtual bool hasVideo() const { return true; }
    301     virtual bool supportsFullscreen() const { return true; }
    302 
    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 
    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 
    370     float maxTimeSeekable() const
    371     {
    372         return m_duration;
    373     }
    374 };
    375 
    376 class MediaPlayerAudioPrivate : public MediaPlayerPrivate {
    377 public:
    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 
    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 
    414     virtual bool hasAudio() const { return true; }
    415     virtual bool hasVideo() const { return false; }
    416     virtual bool supportsFullscreen() const { return false; }
    417 
    418     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    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 
    652 int registerMediaPlayerVideo(JNIEnv* env)
    653 {
    654     return jniRegisterNativeMethods(env, g_ProxyJavaClass,
    655             g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods));
    656 }
    657 
    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