blob: 402734c3ff62cac1adfd220001b40fe1aa7f8d4c [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/android/content_video_view.h"
#include "base/android/jni_android.h"
#include "base/command_line.h"
#include "base/logging.h"
#if !defined(ANDROID_UPSTREAM_BRINGUP)
#include "content/browser/media/media_player_delegate_android.h"
#endif
#include "content/common/android/surface_callback.h"
#include "content/common/android/surface_texture_peer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "jni/ContentVideoView_jni.h"
#include "webkit/media/android/media_metadata_android.h"
using base::android::AttachCurrentThread;
using base::android::CheckException;
using base::android::ScopedJavaGlobalRef;
// The timeout value we should wait after user click the back button on the
// fullscreen view.
static const int kTimeoutMillseconds = 1000;
// ----------------------------------------------------------------------------
// Methods that call to Java via JNI
// ----------------------------------------------------------------------------
namespace content {
// static
bool ContentVideoView::RegisterContentVideoView(JNIEnv* env) {
return RegisterNativesImpl(env);
}
void ContentVideoView::CreateContentVideoView(
MediaPlayerDelegateAndroid* player) {
player_ = player;
if (j_content_video_view_.is_null()) {
JNIEnv* env = AttachCurrentThread();
j_content_video_view_.Reset(Java_ContentVideoView_createContentVideoView(
env, reinterpret_cast<jint>(this)));
} else {
// Just ask video view to reopen the video.
Java_ContentVideoView_openVideo(AttachCurrentThread(),
j_content_video_view_.obj());
}
}
void ContentVideoView::DestroyContentVideoView() {
if (!j_content_video_view_.is_null()) {
Java_ContentVideoView_destroyContentVideoView(AttachCurrentThread());
j_content_video_view_.Reset();
}
}
void ContentVideoView::OnMediaPlayerError(int error_type) {
if (!j_content_video_view_.is_null()) {
Java_ContentVideoView_onMediaPlayerError(AttachCurrentThread(),
j_content_video_view_.obj(),
error_type);
}
}
void ContentVideoView::OnVideoSizeChanged(int width, int height) {
if (!j_content_video_view_.is_null()) {
Java_ContentVideoView_onVideoSizeChanged(AttachCurrentThread(),
j_content_video_view_.obj(),
width,
height);
}
}
void ContentVideoView::OnBufferingUpdate(int percent) {
if (!j_content_video_view_.is_null()) {
Java_ContentVideoView_onBufferingUpdate(AttachCurrentThread(),
j_content_video_view_.obj(),
percent);
}
}
void ContentVideoView::OnPlaybackComplete() {
if (!j_content_video_view_.is_null()) {
Java_ContentVideoView_onPlaybackComplete(AttachCurrentThread(),
j_content_video_view_.obj());
}
}
void ContentVideoView::UpdateMediaMetadata() {
if (!j_content_video_view_.is_null())
UpdateMediaMetadata(AttachCurrentThread(), j_content_video_view_.obj());
}
// ----------------------------------------------------------------------------
ContentVideoView::ContentVideoView() : player_(NULL) {
}
ContentVideoView::~ContentVideoView() {
player_ = NULL;
// If the browser process crashed, just kill the fullscreen view.
DestroyContentVideoView();
}
// ----------------------------------------------------------------------------
// All these functions are called on UI thread
int ContentVideoView::GetVideoWidth(JNIEnv*, jobject obj) const {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return player_ ? player_->GetVideoWidth() : 0;
#else
return 0;
#endif
}
int ContentVideoView::GetVideoHeight(JNIEnv*, jobject obj) const {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return player_ ? player_->GetVideoHeight() : 0;
#else
return 0;
#endif
}
int ContentVideoView::GetDurationInMilliSeconds(JNIEnv*, jobject obj) const {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return player_ ? ConvertSecondsToMilliSeconds(player_->Duration()) : -1;
#else
return -1;
#endif
}
int ContentVideoView::GetCurrentPosition(JNIEnv*, jobject obj) const {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return player_ ? ConvertSecondsToMilliSeconds(player_->CurrentTime()) : 0;
#else
return 0;
#endif
}
bool ContentVideoView::IsPlaying(JNIEnv*, jobject obj) {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return player_ ? player_->IsPlaying() : false;
#else
return false;
#endif
}
void ContentVideoView::SeekTo(JNIEnv*, jobject obj, jint msec) {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (player_)
player_->Seek(static_cast<float>(msec / 1000.0));
#endif
}
webkit_media::MediaMetadataAndroid* ContentVideoView::GetMediaMetadata() {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!player_)
return NULL;
return new webkit_media::MediaMetadataAndroid(player_->GetVideoWidth(),
player_->GetVideoHeight(),
base::TimeDelta::FromSeconds(
player_->Duration()),
base::TimeDelta::FromSeconds(
player_->CurrentTime()),
!player_->IsPlaying(),
player_->CanPause(),
player_->CanSeekForward(),
player_->CanSeekForward());
#else
return NULL;
#endif
}
int ContentVideoView::GetPlayerId(JNIEnv*, jobject obj) const {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return player_ ? player_->player_id() : -1;
#else
return -1;
#endif
}
int ContentVideoView::GetRouteId(JNIEnv*, jobject obj) const {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return player_ ? player_->route_id() : -1;
#else
return -1;
#endif
}
int ContentVideoView::GetRenderHandle(JNIEnv*, jobject obj) const {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
static bool single_process =
CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
if (!player_)
return -1;
if (single_process)
return 0;
return player_->render_handle();
#else
return -1;
#endif
}
void ContentVideoView::Play(JNIEnv*, jobject obj) {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (player_)
player_->Play();
#endif
}
void ContentVideoView::Pause(JNIEnv*, jobject obj) {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (player_)
player_->Pause();
#endif
}
void ContentVideoView::OnTimeout() {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
#endif
timeout_timer_.Stop();
DestroyContentVideoView();
}
int ContentVideoView::ConvertSecondsToMilliSeconds(float seconds) const {
return static_cast<int>(seconds * 1000);
}
// ----------------------------------------------------------------------------
// Methods called from Java via JNI
// ----------------------------------------------------------------------------
void ContentVideoView::DestroyContentVideoView(JNIEnv*, jobject,
jboolean release_media_player) {
#if !defined(ANDROID_UPSTREAM_BRINGUP)
if (player_) {
player_->ExitFullscreen(release_media_player);
// Fire off a timer so that we will close the fullscreen view in case the
// renderer crashes.
timeout_timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(kTimeoutMillseconds),
this, &ContentVideoView::OnTimeout);
}
#endif
}
void ContentVideoView::SetSurface(JNIEnv* env, jobject obj,
jobject surface,
jint route_id,
jint player_id) {
SetSurfaceAsync(env,
surface,
SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE,
route_id,
player_id,
NULL);
}
void ContentVideoView::UpdateMediaMetadata(JNIEnv* env, jobject obj) {
scoped_ptr<webkit_media::MediaMetadataAndroid> metadata(GetMediaMetadata());
Java_ContentVideoView_updateMediaMetadata(env,
obj,
metadata->width,
metadata->height,
metadata->duration.InMilliseconds(),
metadata->can_pause,
metadata->can_seek_forward,
metadata->can_seek_backward);
}
} // namespace content