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