• 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 "GraphicsContext.h"
33 #include "HTMLMediaElement.h"
34 #include "SkiaUtils.h"
35 #include "TilesManager.h"
36 #include "VideoLayerAndroid.h"
37 #include "WebCoreJni.h"
38 #include "WebViewCore.h"
39 #include <GraphicsJNI.h>
40 #include <JNIHelp.h>
41 #include <JNIUtility.h>
42 #include <SkBitmap.h>
43 #include <gui/SurfaceTexture.h>
44 
45 using namespace android;
46 // Forward decl
47 namespace android {
48 sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
49 };
50 
51 namespace WebCore {
52 
53 static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy";
54 static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio";
55 
56 struct MediaPlayerPrivate::JavaGlue {
57     jobject   m_javaProxy;
58     jmethodID m_play;
59     jmethodID m_enterFullscreenForVideoLayer;
60     jmethodID m_teardown;
61     jmethodID m_seek;
62     jmethodID m_pause;
63     // Audio
64     jmethodID m_newInstance;
65     jmethodID m_setDataSource;
66     jmethodID m_getMaxTimeSeekable;
67     // Video
68     jmethodID m_getInstance;
69     jmethodID m_loadPoster;
70 };
71 
~MediaPlayerPrivate()72 MediaPlayerPrivate::~MediaPlayerPrivate()
73 {
74     TilesManager::instance()->videoLayerManager()->removeLayer(m_videoLayer->uniqueId());
75     // m_videoLayer is reference counted, unref is enough here.
76     m_videoLayer->unref();
77     if (m_glue->m_javaProxy) {
78         JNIEnv* env = JSC::Bindings::getJNIEnv();
79         if (env) {
80             env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_teardown);
81             env->DeleteGlobalRef(m_glue->m_javaProxy);
82         }
83     }
84     delete m_glue;
85 }
86 
registerMediaEngine(MediaEngineRegistrar registrar)87 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
88 {
89     registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
90 }
91 
supportsType(const String & type,const String & codecs)92 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
93 {
94     if (WebViewCore::isSupportedMediaMimeType(type))
95         return MediaPlayer::MayBeSupported;
96     return MediaPlayer::IsNotSupported;
97 }
98 
pause()99 void MediaPlayerPrivate::pause()
100 {
101     JNIEnv* env = JSC::Bindings::getJNIEnv();
102     if (!env || !m_glue->m_javaProxy || !m_url.length())
103         return;
104 
105     m_paused = true;
106     m_player->playbackStateChanged();
107     env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_pause);
108     checkException(env);
109 }
110 
setVisible(bool visible)111 void MediaPlayerPrivate::setVisible(bool visible)
112 {
113     m_isVisible = visible;
114     if (m_isVisible)
115         createJavaPlayerIfNeeded();
116 }
117 
seek(float time)118 void MediaPlayerPrivate::seek(float time)
119 {
120     JNIEnv* env = JSC::Bindings::getJNIEnv();
121     if (!env || !m_url.length())
122         return;
123 
124     if (m_glue->m_javaProxy) {
125         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast<jint>(time * 1000.0f));
126         m_currentTime = time;
127     }
128     checkException(env);
129 }
130 
prepareToPlay()131 void MediaPlayerPrivate::prepareToPlay()
132 {
133     // We are about to start playing. Since our Java VideoView cannot
134     // buffer any data, we just simply transition to the HaveEnoughData
135     // state in here. This will allow the MediaPlayer to transition to
136     // the "play" state, at which point our VideoView will start downloading
137     // the content and start the playback.
138     m_networkState = MediaPlayer::Loaded;
139     m_player->networkStateChanged();
140     m_readyState = MediaPlayer::HaveEnoughData;
141     m_player->readyStateChanged();
142 }
143 
MediaPlayerPrivate(MediaPlayer * player)144 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
145     : m_player(player),
146     m_glue(0),
147     m_duration(1), // keep this minimal to avoid initial seek problem
148     m_currentTime(0),
149     m_paused(true),
150     m_readyState(MediaPlayer::HaveNothing),
151     m_networkState(MediaPlayer::Empty),
152     m_poster(0),
153     m_naturalSize(100, 100),
154     m_naturalSizeUnknown(true),
155     m_isVisible(false),
156     m_videoLayer(new VideoLayerAndroid())
157 {
158 }
159 
onEnded()160 void MediaPlayerPrivate::onEnded()
161 {
162     m_currentTime = duration();
163     m_player->timeChanged();
164     m_paused = true;
165     m_player->playbackStateChanged();
166     m_networkState = MediaPlayer::Idle;
167 }
168 
onRequestPlay()169 void MediaPlayerPrivate::onRequestPlay()
170 {
171     play();
172 }
173 
onRestoreState()174 void MediaPlayerPrivate::onRestoreState()
175 {
176     if (!m_paused) {
177         //Kick off a JNI call to start the video.
178         play();
179     }
180 }
181 
onPaused()182 void MediaPlayerPrivate::onPaused()
183 {
184     m_paused = true;
185     m_player->playbackStateChanged();
186     m_networkState = MediaPlayer::Idle;
187     m_player->playbackStateChanged();
188 }
189 
onTimeupdate(int position)190 void MediaPlayerPrivate::onTimeupdate(int position)
191 {
192     m_currentTime = position / 1000.0f;
193     m_player->timeChanged();
194 }
195 
onStopFullscreen(bool stillPlaying)196 void MediaPlayerPrivate::onStopFullscreen(bool stillPlaying)
197 {
198     if (m_player && m_player->mediaPlayerClient()) {
199         Document* doc = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
200         if (doc) {
201             HTMLMediaElement* element =
202                 static_cast<HTMLMediaElement*>(doc->webkitCurrentFullScreenElement());
203             element->exitFullscreen();
204             doc->webkitDidExitFullScreenForElement(element);
205 
206             if (stillPlaying)
207                 element->play(true);
208         }
209     }
210 }
211 
212 class MediaPlayerVideoPrivate : public MediaPlayerPrivate {
213 public:
load(const String & url)214     void load(const String& url)
215     {
216         m_url = url;
217         // Cheat a bit here to make sure Window.onLoad event can be triggered
218         // at the right time instead of real video play time, since only full
219         // screen video play is supported in Java's VideoView.
220         // See also comments in prepareToPlay function.
221         m_networkState = MediaPlayer::Loading;
222         m_player->networkStateChanged();
223         m_readyState = MediaPlayer::HaveCurrentData;
224         m_player->readyStateChanged();
225     }
226 
play()227     void play()
228     {
229         JNIEnv* env = JSC::Bindings::getJNIEnv();
230         if (!env || !m_url.length() || !m_glue->m_javaProxy)
231             return;
232 
233         m_paused = false;
234         m_player->playbackStateChanged();
235 
236         if (m_currentTime == duration())
237             m_currentTime = 0;
238 
239         jstring jUrl = wtfStringToJstring(env, m_url);
240         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl,
241                             static_cast<jint>(m_currentTime * 1000.0f),
242                             m_videoLayer->uniqueId());
243         env->DeleteLocalRef(jUrl);
244 
245         checkException(env);
246     }
247 
enterFullscreenMode()248     void enterFullscreenMode()
249     {
250         JNIEnv* env = JSC::Bindings::getJNIEnv();
251         if (!env || !m_url.length() || !m_glue->m_javaProxy)
252             return;
253 
254         jstring jUrl = wtfStringToJstring(env, m_url);
255         env->CallVoidMethod(m_glue->m_javaProxy,
256                             m_glue->m_enterFullscreenForVideoLayer, jUrl,
257                             m_videoLayer->uniqueId());
258         env->DeleteLocalRef(jUrl);
259 
260         checkException(env);
261     }
262 
canLoadPoster() const263     bool canLoadPoster() const { return true; }
setPoster(const String & url)264     void setPoster(const String& url)
265     {
266         if (m_posterUrl == url)
267             return;
268 
269         m_posterUrl = url;
270         JNIEnv* env = JSC::Bindings::getJNIEnv();
271         if (!env || !m_glue->m_javaProxy || !m_posterUrl.length())
272             return;
273         // Send the poster
274         jstring jUrl = wtfStringToJstring(env, m_posterUrl);
275         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
276         env->DeleteLocalRef(jUrl);
277     }
paint(GraphicsContext * ctxt,const IntRect & r)278     void paint(GraphicsContext* ctxt, const IntRect& r)
279     {
280         if (ctxt->paintingDisabled())
281             return;
282 
283         if (!m_isVisible)
284             return;
285 
286         if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
287             return;
288 
289         // We paint with the following rules in mind:
290         // - only downscale the poster, never upscale
291         // - maintain the natural aspect ratio of the poster
292         // - the poster should be centered in the target rect
293         float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
294         int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
295         int posterHeight = posterWidth / originalRatio;
296         int posterX = ((r.width() - posterWidth) / 2) + r.x();
297         int posterY = ((r.height() - posterHeight) / 2) + r.y();
298         IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
299         ctxt->platformContext()->drawBitmapRect(*m_poster, 0, targetRect);
300     }
301 
onPosterFetched(SkBitmap * poster)302     void onPosterFetched(SkBitmap* poster)
303     {
304         m_poster = poster;
305         if (m_naturalSizeUnknown) {
306             // We had to fake the size at startup, or else our paint
307             // method would not be called. If we haven't yet received
308             // the onPrepared event, update the intrinsic size to the size
309             // of the poster. That will be overriden when onPrepare comes.
310             // In case of an error, we should report the poster size, rather
311             // than our initial fake value.
312             m_naturalSize = IntSize(poster->width(), poster->height());
313             m_player->sizeChanged();
314         }
315         // At this time, we know that the proxy has been setup. And it is the
316         // right time to trigger autoplay through the HTMLMediaElement state
317         // change. Since we are using the java MediaPlayer, so we have to
318         // pretend that the MediaPlayer has enough data.
319         m_readyState = MediaPlayer::HaveEnoughData;
320         m_player->readyStateChanged();
321 
322     }
323 
onPrepared(int duration,int width,int height)324     void onPrepared(int duration, int width, int height)
325     {
326         m_duration = duration / 1000.0f;
327         m_naturalSize = IntSize(width, height);
328         m_naturalSizeUnknown = false;
329         m_player->durationChanged();
330         m_player->sizeChanged();
331         TilesManager::instance()->videoLayerManager()->updateVideoLayerSize(
332             m_player->platformLayer()->uniqueId(), width * height,
333             width / (float)height);
334     }
335 
hasAudio() const336     virtual bool hasAudio() const { return false; } // do not display the audio UI
hasVideo() const337     virtual bool hasVideo() const { return true; }
supportsFullscreen() const338     virtual bool supportsFullscreen() const { return true; }
339 
MediaPlayerVideoPrivate(MediaPlayer * player)340     MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player)
341     {
342         JNIEnv* env = JSC::Bindings::getJNIEnv();
343         if (!env)
344             return;
345 
346         jclass clazz = env->FindClass(g_ProxyJavaClass);
347 
348         if (!clazz)
349             return;
350 
351         m_glue = new JavaGlue;
352         m_glue->m_getInstance =
353             env->GetStaticMethodID(clazz, "getInstance",
354                                    "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;");
355         m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V");
356         m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;II)V");
357         m_glue->m_enterFullscreenForVideoLayer =
358             env->GetMethodID(clazz, "enterFullscreenForVideoLayer", "(Ljava/lang/String;I)V");
359 
360         m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
361         m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
362         m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
363         m_glue->m_javaProxy = 0;
364         env->DeleteLocalRef(clazz);
365         // An exception is raised if any of the above fails.
366         checkException(env);
367     }
368 
createJavaPlayerIfNeeded()369     void createJavaPlayerIfNeeded()
370     {
371         // Check if we have been already created.
372         if (m_glue->m_javaProxy)
373             return;
374 
375         JNIEnv* env = JSC::Bindings::getJNIEnv();
376         if (!env)
377             return;
378 
379         jclass clazz = env->FindClass(g_ProxyJavaClass);
380 
381         if (!clazz)
382             return;
383 
384         jobject obj = 0;
385 
386         FrameView* frameView = m_player->frameView();
387         if (!frameView)
388             return;
389         AutoJObject javaObject = WebViewCore::getWebViewCore(frameView)->getJavaObject();
390         if (!javaObject.get())
391             return;
392 
393         // Get the HTML5VideoViewProxy instance
394         obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, javaObject.get(), this);
395         m_glue->m_javaProxy = env->NewGlobalRef(obj);
396         // Send the poster
397         jstring jUrl = 0;
398         if (m_posterUrl.length())
399             jUrl = wtfStringToJstring(env, m_posterUrl);
400         // Sending a NULL jUrl allows the Java side to try to load the default poster.
401         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
402         if (jUrl)
403             env->DeleteLocalRef(jUrl);
404 
405         // Clean up.
406         env->DeleteLocalRef(obj);
407         env->DeleteLocalRef(clazz);
408         checkException(env);
409     }
410 
maxTimeSeekable() const411     float maxTimeSeekable() const
412     {
413         return m_duration;
414     }
415 };
416 
417 class MediaPlayerAudioPrivate : public MediaPlayerPrivate {
418 public:
load(const String & url)419     void load(const String& url)
420     {
421         m_url = url;
422         JNIEnv* env = JSC::Bindings::getJNIEnv();
423         if (!env || !m_url.length())
424             return;
425 
426         createJavaPlayerIfNeeded();
427 
428         if (!m_glue->m_javaProxy)
429             return;
430 
431         jstring jUrl = wtfStringToJstring(env, m_url);
432         // start loading the data asynchronously
433         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_setDataSource, jUrl);
434         env->DeleteLocalRef(jUrl);
435         checkException(env);
436     }
437 
play()438     void play()
439     {
440         JNIEnv* env = JSC::Bindings::getJNIEnv();
441         if (!env || !m_url.length())
442             return;
443 
444         createJavaPlayerIfNeeded();
445 
446         if (!m_glue->m_javaProxy)
447             return;
448 
449         m_paused = false;
450         m_player->playbackStateChanged();
451         env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play);
452         checkException(env);
453     }
454 
hasAudio() const455     virtual bool hasAudio() const { return true; }
hasVideo() const456     virtual bool hasVideo() const { return false; }
supportsFullscreen() const457     virtual bool supportsFullscreen() const { return false; }
458 
maxTimeSeekable() const459     float maxTimeSeekable() const
460     {
461         if (m_glue->m_javaProxy) {
462             JNIEnv* env = JSC::Bindings::getJNIEnv();
463             if (env) {
464                 float maxTime = env->CallFloatMethod(m_glue->m_javaProxy,
465                                                      m_glue->m_getMaxTimeSeekable);
466                 checkException(env);
467                 return maxTime;
468             }
469         }
470         return 0;
471     }
472 
MediaPlayerAudioPrivate(MediaPlayer * player)473     MediaPlayerAudioPrivate(MediaPlayer* player) : MediaPlayerPrivate(player)
474     {
475         JNIEnv* env = JSC::Bindings::getJNIEnv();
476         if (!env)
477             return;
478 
479         jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
480 
481         if (!clazz)
482             return;
483 
484         m_glue = new JavaGlue;
485         m_glue->m_newInstance = env->GetMethodID(clazz, "<init>", "(Landroid/webkit/WebViewCore;I)V");
486         m_glue->m_setDataSource = env->GetMethodID(clazz, "setDataSource", "(Ljava/lang/String;)V");
487         m_glue->m_play = env->GetMethodID(clazz, "play", "()V");
488         m_glue->m_getMaxTimeSeekable = env->GetMethodID(clazz, "getMaxTimeSeekable", "()F");
489         m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
490         m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
491         m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
492         m_glue->m_javaProxy = 0;
493         env->DeleteLocalRef(clazz);
494         // An exception is raised if any of the above fails.
495         checkException(env);
496     }
497 
createJavaPlayerIfNeeded()498     void createJavaPlayerIfNeeded()
499     {
500         // Check if we have been already created.
501         if (m_glue->m_javaProxy)
502             return;
503 
504         JNIEnv* env = JSC::Bindings::getJNIEnv();
505         if (!env)
506             return;
507 
508         jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
509 
510         if (!clazz)
511             return;
512 
513         FrameView* frameView = m_player->mediaPlayerClient()->mediaPlayerOwningDocument()->view();
514         if (!frameView)
515             return;
516         AutoJObject javaObject = WebViewCore::getWebViewCore(frameView)->getJavaObject();
517         if (!javaObject.get())
518             return;
519 
520         jobject obj = 0;
521 
522         // Get the HTML5Audio instance
523         obj = env->NewObject(clazz, m_glue->m_newInstance, javaObject.get(), this);
524         m_glue->m_javaProxy = env->NewGlobalRef(obj);
525 
526         // Clean up.
527         if (obj)
528             env->DeleteLocalRef(obj);
529         env->DeleteLocalRef(clazz);
530         checkException(env);
531     }
532 
onPrepared(int duration,int width,int height)533     void onPrepared(int duration, int width, int height)
534     {
535         // Android media player gives us a duration of 0 for a live
536         // stream, so in that case set the real duration to infinity.
537         // We'll still be able to handle the case that we genuinely
538         // get an audio clip with a duration of 0s as we'll get the
539         // ended event when it stops playing.
540         if (duration > 0) {
541             m_duration = duration / 1000.0f;
542         } else {
543             m_duration = std::numeric_limits<float>::infinity();
544         }
545         m_player->durationChanged();
546         m_player->sizeChanged();
547         m_player->prepareToPlay();
548     }
549 };
550 
create(MediaPlayer * player)551 MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
552 {
553     if (player->mediaElementType() == MediaPlayer::Video)
554        return new MediaPlayerVideoPrivate(player);
555     return new MediaPlayerAudioPrivate(player);
556 }
557 
558 }
559 
560 namespace android {
561 
OnPrepared(JNIEnv * env,jobject obj,int duration,int width,int height,int pointer)562 static void OnPrepared(JNIEnv* env, jobject obj, int duration, int width, int height, int pointer)
563 {
564     if (pointer) {
565         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
566         player->onPrepared(duration, width, height);
567     }
568 }
569 
OnEnded(JNIEnv * env,jobject obj,int pointer)570 static void OnEnded(JNIEnv* env, jobject obj, int pointer)
571 {
572     if (pointer) {
573         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
574         player->onEnded();
575     }
576 }
577 
OnRequestPlay(JNIEnv * env,jobject obj,int pointer)578 static void OnRequestPlay(JNIEnv* env, jobject obj, int pointer)
579 {
580     if (pointer) {
581         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
582         player->onRequestPlay();
583     }
584 }
585 
OnPaused(JNIEnv * env,jobject obj,int pointer)586 static void OnPaused(JNIEnv* env, jobject obj, int pointer)
587 {
588     if (pointer) {
589         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
590         player->onPaused();
591     }
592 }
593 
OnPosterFetched(JNIEnv * env,jobject obj,jobject poster,int pointer)594 static void OnPosterFetched(JNIEnv* env, jobject obj, jobject poster, int pointer)
595 {
596     if (!pointer || !poster)
597         return;
598 
599     WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
600     SkBitmap* posterNative = GraphicsJNI::getNativeBitmap(env, poster);
601     if (!posterNative)
602         return;
603     player->onPosterFetched(posterNative);
604 }
605 
OnBuffering(JNIEnv * env,jobject obj,int percent,int pointer)606 static void OnBuffering(JNIEnv* env, jobject obj, int percent, int pointer)
607 {
608     if (pointer) {
609         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
610         // TODO: player->onBuffering(percent);
611     }
612 }
613 
OnTimeupdate(JNIEnv * env,jobject obj,int position,int pointer)614 static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer)
615 {
616     if (pointer) {
617         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
618         player->onTimeupdate(position);
619     }
620 }
621 
OnRestoreState(JNIEnv * env,jobject obj,int pointer)622 static void OnRestoreState(JNIEnv* env, jobject obj, int pointer)
623 {
624     if (pointer) {
625         WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
626         player->onRestoreState();
627     }
628 }
629 
630 
631 // This is called on the UI thread only.
632 // The video layers are composited on the webkit thread and then copied over
633 // to the UI thread with the same ID. For rendering, we are only using the
634 // video layers on the UI thread. Therefore, on the UI thread, we have to use
635 // the videoLayerId from Java side to find the exact video layer in the tree
636 // to set the surface texture.
637 // Every time a play call into Java side, the videoLayerId will be sent and
638 // saved in Java side. Then every time setBaseLayer call, the saved
639 // videoLayerId will be passed to this function to find the Video Layer.
640 // Return value: true when the video layer is found.
SendSurfaceTexture(JNIEnv * env,jobject obj,jobject surfTex,int baseLayer,int videoLayerId,int textureName,int playerState)641 static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex,
642                                int baseLayer, int videoLayerId,
643                                int textureName, int playerState) {
644     if (!surfTex)
645         return false;
646 
647     sp<SurfaceTexture> texture = android::SurfaceTexture_getSurfaceTexture(env, surfTex);
648     if (!texture.get())
649         return false;
650 
651     BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(baseLayer);
652     if (!layerImpl)
653         return false;
654 
655     VideoLayerAndroid* videoLayer =
656         static_cast<VideoLayerAndroid*>(layerImpl->findById(videoLayerId));
657     if (!videoLayer)
658         return false;
659 
660     // Set the SurfaceTexture to the layer we found
661     videoLayer->setSurfaceTexture(texture, textureName, static_cast<PlayerState>(playerState));
662     return true;
663 }
664 
OnStopFullscreen(JNIEnv * env,jobject obj,int stillPlaying,int pointer)665 static void OnStopFullscreen(JNIEnv* env, jobject obj, int stillPlaying, int pointer)
666 {
667     if (pointer) {
668         WebCore::MediaPlayerPrivate* player =
669             reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
670         player->onStopFullscreen(stillPlaying);
671     }
672 }
673 
674 /*
675  * JNI registration
676  */
677 static JNINativeMethod g_MediaPlayerMethods[] = {
678     { "nativeOnPrepared", "(IIII)V",
679         (void*) OnPrepared },
680     { "nativeOnEnded", "(I)V",
681         (void*) OnEnded },
682     { "nativeOnStopFullscreen", "(II)V",
683         (void*) OnStopFullscreen },
684     { "nativeOnPaused", "(I)V",
685         (void*) OnPaused },
686     { "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V",
687         (void*) OnPosterFetched },
688     { "nativeOnRestoreState", "(I)V",
689         (void*) OnRestoreState },
690     { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z",
691         (void*) SendSurfaceTexture },
692     { "nativeOnTimeupdate", "(II)V",
693         (void*) OnTimeupdate },
694 };
695 
696 static JNINativeMethod g_MediaAudioPlayerMethods[] = {
697     { "nativeOnBuffering", "(II)V",
698         (void*) OnBuffering },
699     { "nativeOnEnded", "(I)V",
700         (void*) OnEnded },
701     { "nativeOnPrepared", "(IIII)V",
702         (void*) OnPrepared },
703     { "nativeOnRequestPlay", "(I)V",
704         (void*) OnRequestPlay },
705     { "nativeOnTimeupdate", "(II)V",
706         (void*) OnTimeupdate },
707 };
708 
registerMediaPlayerVideo(JNIEnv * env)709 int registerMediaPlayerVideo(JNIEnv* env)
710 {
711     return jniRegisterNativeMethods(env, g_ProxyJavaClass,
712             g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods));
713 }
714 
registerMediaPlayerAudio(JNIEnv * env)715 int registerMediaPlayerAudio(JNIEnv* env)
716 {
717     return jniRegisterNativeMethods(env, g_ProxyJavaClassAudio,
718             g_MediaAudioPlayerMethods, NELEM(g_MediaAudioPlayerMethods));
719 }
720 
721 }
722 #endif // VIDEO
723