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/GLConsumer.h> 44 45 using namespace android; 46 // Forward decl 47 namespace android { 48 sp<GLConsumer> 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 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 87 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) 88 { 89 registrar(create, getSupportedTypes, supportsType, 0, 0, 0); 90 } 91 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 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 111 void MediaPlayerPrivate::setVisible(bool visible) 112 { 113 m_isVisible = visible; 114 if (m_isVisible) 115 createJavaPlayerIfNeeded(); 116 } 117 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 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 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 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 169 void MediaPlayerPrivate::onRequestPlay() 170 { 171 play(); 172 } 173 174 void MediaPlayerPrivate::onRestoreState() 175 { 176 if (!m_paused) { 177 //Kick off a JNI call to start the video. 178 play(); 179 } 180 } 181 182 void MediaPlayerPrivate::onPaused() 183 { 184 m_paused = true; 185 m_player->playbackStateChanged(); 186 m_networkState = MediaPlayer::Idle; 187 m_player->playbackStateChanged(); 188 } 189 190 void MediaPlayerPrivate::onTimeupdate(int position) 191 { 192 m_currentTime = position / 1000.0f; 193 m_player->timeChanged(); 194 } 195 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: 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 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 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 263 bool canLoadPoster() const { return true; } 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 } 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 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 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 336 virtual bool hasAudio() const { return false; } // do not display the audio UI 337 virtual bool hasVideo() const { return true; } 338 virtual bool supportsFullscreen() const { return true; } 339 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 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 411 float maxTimeSeekable() const 412 { 413 return m_duration; 414 } 415 }; 416 417 class MediaPlayerAudioPrivate : public MediaPlayerPrivate { 418 public: 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 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 455 virtual bool hasAudio() const { return true; } 456 virtual bool hasVideo() const { return false; } 457 virtual bool supportsFullscreen() const { return false; } 458 459 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 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 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 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 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 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 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 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 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 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 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 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 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. 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<GLConsumer> 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 GLConsumer to the layer we found 661 videoLayer->setSurfaceTexture(texture, textureName, static_cast<PlayerState>(playerState)); 662 return true; 663 } 664 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 709 int registerMediaPlayerVideo(JNIEnv* env) 710 { 711 return jniRegisterNativeMethods(env, g_ProxyJavaClass, 712 g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods)); 713 } 714 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